【问题标题】:Why do I still burn out the stack using tail recursive Fibonacci algorithm?为什么我仍然使用尾递归斐波那契算法烧毁堆栈?
【发布时间】:2013-03-10 10:49:39
【问题描述】:

在 n=1000 之前堆栈溢出。是因为对 long[] 参数的引用,JVM 觉得需要保留每个堆栈帧(疯狂猜测),还是我做错了什么?

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        fibonacciMemoized(1000);
        long end = System.currentTimeMillis();
        System.out.println("\nTotal run time: " + (end-start));
    }

    public static void fibonacciMemoized(int n) {
        long[] fibMemos = new long[n+1];
        for (int i = 0;  i < fibMemos.length; i++) {
            fibMemos[i] = Long.MAX_VALUE;
        }
        long fibResult = fib(n, 1, 0, fibMemos);
        System.out.println(fibResult);
    }

    public static long fib(int n, long fibAcc, long fibPrev, long[] fibMemos) {
        if (fibMemos[n] != Long.MAX_VALUE){
            return fibMemos[n];
        } else if (n == 0) {
            return fibPrev;
        } else if (n == 1){
            return fibAcc;
        } else {
            long result = fib(n-1, fibAcc+fibPrev, fibAcc, fibMemos);
            fibMemos[n] = result;
            return result;
        }
    }

【问题讨论】:

    标签: java stack-overflow dynamic-programming tail-recursion memoization


    【解决方案1】:

    记忆化的关键问题是记忆化函数的后续调用将使用相同参数的预先计算值。

    在您的代码中,您之前没有调用过该函数,因此没有以前的结果可以重用,并且您开始使用值 1000 调用它,这会在 fib() 的末尾使用 @ 进行递归调用987654322@,所以你用 1000 次递归调用炸毁了堆栈。

    【讨论】:

    • 如何以自上而下的方式将值输入 fibMemos?
    • 好的,我想我明白了,这种记忆方案仅在您仍在进行 2 次递归调用时才有效,例如 'fib(n-2) + fib(n-1)'.... .
    【解决方案2】:

    尝试使用增加堆栈的选项来运行它,例如 java -Xss4m 或更多。

    注意:使用 -Xss 设置每个线程的堆栈大小,这是一个非常糟糕的主意。

    【讨论】:

      【解决方案3】:

      我想这更像是一个答案而不是评论:

      为什么我仍然使用尾递归斐波那契算法烧毁堆栈?

      因为 Java 不支持尾调用消除。

      【讨论】:

      • 支持,你自己写,呵呵。
      • @Thomas:好吧,我想任何带有循环的语言都“支持”消除尾调用:)
      • 这解释了很多哈哈。
      • @ThomasMcLeod - 这就像说汇编语言支持函数式编程。这不是人们通常所说的“支持”。
      • 在这种情况下,正确的答案也是“因为您实际上没有实现尾递归函数”。我的意思是,无论如何它都无济于事,但是foo(X): foo(X); bar=Y 是如何进行尾递归的呢?
      猜你喜欢
      • 2014-04-02
      • 2012-12-29
      • 2011-03-24
      • 2012-05-06
      • 1970-01-01
      • 1970-01-01
      • 2010-12-03
      • 2014-11-14
      相关资源
      最近更新 更多