Java 为什么我仍然使用尾部递归斐波那契算法烧坏堆栈?
n=1000之前的堆栈溢出。是因为对long[]参数的引用,JVM觉得需要保留每个堆栈帧(胡乱猜测),还是我做了其他错误的事情Java 为什么我仍然使用尾部递归斐波那契算法烧坏堆栈?,java,stack-overflow,dynamic-programming,tail-recursion,memoization,Java,Stack Overflow,Dynamic Programming,Tail Recursion,Memoization,n=1000之前的堆栈溢出。是因为对long[]参数的引用,JVM觉得需要保留每个堆栈帧(胡乱猜测),还是我做了其他错误的事情 public static void main(String[] args) { long start = System.currentTimeMillis(); fibonacciMemoized(1000); long end = System.currentTimeMillis(); Syst
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;
}
}
publicstaticvoidmain(字符串[]args){
长启动=System.currentTimeMillis();
斐波那契化(1000);
long end=System.currentTimeMillis();
System.out.println(“\n总运行时间:”+(结束-开始));
}
公共静态无效光纤接入(int n){
long[]fibmomes=新的long[n+1];
对于(int i=0;i
我想这与其说是评论,不如说是回答:
为什么我仍然使用尾部递归斐波那契算法烧坏堆栈
因为Java不支持尾部调用消除。尝试使用选项来增加堆栈,比如Java-Xss4m或更多
注意:使用-Xss设置每个线程的堆栈大小,这是一个非常糟糕的主意。记忆化的关键问题是,记忆化函数的后续调用将对相同的参数使用预先计算的值
在您的代码中,您以前没有调用过该函数,因此之前没有可重复使用的结果,您开始使用值1000调用它,这将在
fib()的末尾使用fib(n-1,fibAcc+fibprov,fibAcc,fibmomes)进行递归调用。
,所以你用1000个递归调用来破坏堆栈。它支持它,你只需要给自己写,呵呵。@Thomas:是的,我想任何带有循环的语言都“支持”消除尾部调用:)这解释了很多,哈哈。@Thomasmclod-这就像说汇编语言支持函数式编程一样。这不是人们通常所说的“支持”的意思。在这种情况下,正确的答案也是“因为您实际上没有实现递归函数”。我的意思是,是的,它在任何情况下都不会有帮助,但是foo(X):foo(X);bar=Y
be tail recursive?如何以自上而下的方式将值输入到FIBMomes中?好的,我想我明白了,这种记忆化方案只有在您仍在进行两个递归调用时才有效,比如'fib(n-2)+fib(n-1)。。。。。