2010-09-19 97 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或其他函数式语言中编程,那么这种风格将得到适当和有效的支持。