2010-09-19 95 views
2

這種遞歸有什麼問題Java此遞歸中的Stackoverflow錯誤

public class findPyt 
{ 
    public static int sum = 0; 
    public static void main(String[] args) 
    { 
     findP(3, 4, 5); 
    } 

    public static void findP(int a, int b, int c) 
    { 
     sum = a+b+c; 

     if (sum == 1000) 
     { 
      System.out.println("The Triplets are: "+ a +","+ b +","+ c); 
     } 
     else 
     { 
      findP(a*2, b*2, c*2); 
     } 
    } 
} 

我得到這個異常:

Exception in thread "main" java.lang.StackOverflowError 
    at hello.findP(hello.java:12) 
    at hello.findP(hello.java:19) 

當我嘗試紅寶石做相同的,我得到這個:

SystemStackError: stack level too deep 


def pythagoreanTriples(a=3, b=4, c=5) 

    if (a+b+c) == 1000 
     puts "The Triplets are: "+ a +","+ b +","+ c 
    else 
    pythagoreanTriples(a*2, b*2, c*2) 
    end 
end 

回答

12

嘗試改變sum == 1000sum >= 1000。沒有三分之一到正好 1000,所以它跳過終止條件。

此外,您的Ruby代碼與您的Java代碼不匹配(您缺少else)。即使它找到了1000的總和,它也會打印該消息,並繼續遞歸直到崩潰。

+1

啊......錯過了那個基地的條件!謝謝!有效! – zengr 2010-09-19 22:50:36

+0

更新了ruby代碼。 – zengr 2010-09-19 22:51:45

1

那麼,你在這裏構造了無限遞歸,沒有任何東西阻止它。當然,它會因堆棧滿了錯誤而中斷。

3

那麼,如果你看看你的執行遞歸的方法,唯一的退出條件是當sum == 1000.你當前的輸入值是3,4和5.這個總和是12.條件不是保持真實,所以它嘗試下一個集合,其中sum = 24。然後48,96等等。總和永遠不會是1000,所以遞歸永遠不會結束。

2

3 + 4 + 5 = 12

的a * 2 + b *表2 + C * 2 =(A + B + C)* 2

12 * 2 * 2 = 12 * 4

現在,讓我們來看看:你的程序將停止時的總和等於1000 這永遠不會發生,順序將是:

12 24 48 96 192 384 768 1536 ...

除非某種整數溢出r你永遠不會達到1000. 而且,因爲你正在使用遞歸,所以最終會發生堆棧溢出(如果你設法解決問題而不遞歸,它將是一個無限循環)

0

順便說一句,你乘以兩。你需要提高到2的能力,所以a^2或a ** 2。

我基於此代碼中的單詞「pythagoreanTriples」。

+0

。例如,3,4,5和6,8,10都是畢達哥拉斯三元組,而9,16,25則不是。 a^2 + b^2 = c^2是齊次的(所有項具有相同的程度),對於所有這些方程乘以常數給出了另一個解。 – Blaisorblade 2010-09-19 22:56:35

+0

http://projecteuler.net/index.php?section=problems&id=9 – 2010-09-19 23:43:37

+0

您的觀點是什麼?我知道三重奏是什麼。什麼可能會讓你困惑的是,該算法不能驗證三元組是否真的是這樣,因此它不會平分任何數字。它只知道3,4,5是一個三元組(你也知道它,不是嗎?),3 * 2^n,4 * 2^n,5 * 2^n也是。 如果您的觀點是該代碼是該ProjectEuler問題的一個錯誤解決方案,請說明它,然後請注意您的提案不能解決問題,它只會讓事情變得更糟,因爲它不會產生新的三元組。 – Blaisorblade 2010-10-09 20:19:04

1

除了其他答案所描述的代碼中的錯誤之外,無論如何,以這種方式在Java中使用遞歸都是有問題的。您正在使用尾遞歸,因此編譯器或JVM可以將該調用轉換爲跳到該過程的開頭,並且不佔用堆棧空間;然而,這沒有完成(爲了保存精確的堆棧跟蹤)。

例如,在Java中以這種方式處理列表會導致您的代碼被限制爲在堆棧溢出之前僅處理有限長度的列表,即使它在工作時也會導致性能降低和內存消耗增加。但是崩潰的可能性(比如說超過一百萬個元素,因爲堆棧默認是8MiB)更重要。

如果您要在Scala或其他函數式語言中編程,那麼這種風格將得到適當和有效的支持。