[英]Stack Overflow when computing n = ~11000 + fibonacci recursive method with memoization
我有一個程序可以使用遞歸方法並使用記憶來計算第n個斐波那契數。
我最多達到n = 11000,並且遇到了stackoverflow異常。 有人可以幫我解決這個問題嗎?
這是我的代碼:
public class BigInt {
static BigInteger[] fval;
public static void main(String[] args) {
int index;
Scanner input = new Scanner(System.in);
index = input.nextInt();
fval = new BigInteger[index + 1];
System.out.println(fib_rec(index));
}
public static BigInteger fib_rec(int index) {
BigInteger result = BigInteger.ONE;
if (index <= 2) {
return result;
} else {
if (fval[index] != null) {
result = fval[index];
} else {
result = fib_rec(index - 1).add(fib_rec(index - 2));
fval[index] = result;
}
return result;
}
}
您的記憶不會改變遞歸的深度...在調用fib_rec(n)
,它調用fib_rec(n-1)
,在調用fib_rec(n-2)
等時。如果反轉調用順序(這樣您可以執行fib_rec(index - 2).add(fib_rec(index - 1))
,這樣可以將堆棧深度大致減少一半,因為您需要將根部的距離減少兩倍,然后填補空白從頭到尾的堆棧深度為一,這要歸功於您的備忘錄。
但是,如果不對算法進行更戲劇性的重寫,就無法避免堆棧深度問題。
必然
對於足夠大的輸入值, StackOverflowError
本質上是不可修復的。 這個觀點有兩個方面。 首先, Java沒有尾調用優化 。 其次,對於每個遞歸調用,Java必須分配一些內存,例如用於參數。 即使您的方法沒有參數,Java也需要一點內存來存儲要在方法調用結束后跳轉到的地址。 因此,無論大小,最終您都將耗盡內存。 您可以通過使用更多堆棧內存啟動JVM來延長不可避免的時間。 該選項(以及其他選項)可以在此處找到。
我們可以做得更好嗎?
我們可以。 但不能使用遞歸算法。 我們需要將此遞歸算法轉換為迭代算法。 實際上, 每次遞歸都可以迭代進行轉換,反之亦然 。 僅憑這還不夠,因為您的算法具有線性內存復雜性。 實際上,我們僅需要兩個值即可計算下一個斐波那契數。 這導致以下方法(偽代碼):
int fibonacci(int nth)
if nth is smaller than 0
then halt and catch fire
if nth is smaller than 2
then return nth
int last <- 1
int secondToLast <- 0;
for (int ith <- 2; ith less or equal to nth, increment ith)
int tmp <- last + secondToLast
secondToLast <- last
last <- tmp
end for
return last;
上面的算法具有線性時間復雜度(假設可以在恆定時間內完成加法)和恆定內存復雜度,從而解決了您的問題。
使用備忘錄時避免遞歸 。 這是一個例子:
public class BigInt {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int index = input.nextInt();
System.out.println(fib_rec(index));
}
public static BigInteger fib_rec(int index) {
if (index <= 2) {
return BigInteger.ONE;
}
BigInteger[] fval = new BigInteger[index + 1];
fval[0] = BigInteger.ONE;
fval[1] = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
fval[i] = fval[i-1].add(fval[i-2]);
}
return fval[n];
}
}
}
出現stackoverflow的原因是內存不足。 增加可用內存,尤其是增加堆棧大小。 只需添加-Xss1024mb或您喜歡的任何大小即可。
處理這種情況的最好方法是實際上有一個更好的算法,這樣您就不需要消耗大量內存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.