Java 堆栈溢出错误

Java 堆栈溢出错误,java,recursion,stack-overflow,backtracking,Java,Recursion,Stack Overflow,Backtracking,我正试图解决一个需要递归回溯的问题,而我的解决方案会产生堆栈溢出错误。我知道此错误通常表示终止条件不好,但我的终止条件似乎是正确的。除了糟糕的终止条件外,是否还有其他可能导致stackoverflow错误的因素?我怎样才能找出问题所在 编辑:抱歉,试图发布代码,但太难看了。如果代码正确,那么堆栈对于您的问题来说太小了。我们没有真正的图灵机器 正如@unreputable所说,即使您的代码具有正确的终止条件,也可能是因为问题对于堆栈来说太大了(因此在达到条件之前堆栈已耗尽)。还有第三种可能性:递归

我正试图解决一个需要递归回溯的问题,而我的解决方案会产生堆栈溢出错误。我知道此错误通常表示终止条件不好,但我的终止条件似乎是正确的。除了糟糕的终止条件外,是否还有其他可能导致stackoverflow错误的因素?我怎样才能找出问题所在


编辑:抱歉,试图发布代码,但太难看了。

如果代码正确,那么堆栈对于您的问题来说太小了。我们没有真正的图灵机器

正如@unreputable所说,即使您的代码具有正确的终止条件,也可能是因为问题对于堆栈来说太大了(因此在达到条件之前堆栈已耗尽)。还有第三种可能性:递归已进入循环。例如,在通过图形进行深度优先搜索时,如果您忘记将节点标记为已访问,则最终将进入圆圈,重新访问您已经看到的节点


您如何确定您处于这三种情况中的哪一种?设法描述每个递归调用的“位置”(这通常涉及函数参数)。例如,如果您正在编写一个图算法,其中函数在相邻节点上调用自身,那么节点名或节点索引是递归函数所在位置的良好描述。在递归函数的顶部,您可以打印描述,然后您将看到函数的功能,也许您可以判断它是否做了正确的事情,或者它是否在循环中。您还可以将描述存储在HashMap中,以检测是否已输入圆。

如果问题太大而无法在默认堆栈限制大小内修复,则可以使用-Xss选项为堆栈提供更多内存。

您可以使用堆栈的循环,而不是使用递归。例如,代替(伪代码):

使用:


简而言之,通过将状态保存在本地堆栈中来模拟递归。

有两个常见的编码错误可能会导致程序进入无限循环(从而导致堆栈溢出):

  • 不良终止条件
  • 错误的递归调用
例如:

public static int factorial( int n ){
    if( n < n ) // Bad termination condition
        return 1;
    else
        return n*factorial(n+1); // Bad recursion call
}
公共静态整数阶乘(int n){
if(n

否则,您的程序可能运行正常,堆栈太小。

正如其他人已经提到的,可能有一些原因:

  • 您的代码在本质上或递归逻辑上存在问题。它必须是任何递归函数的停止条件、基本情况或终止点
  • 内存太小,无法将递归调用的数量保留在堆栈中。大斐波那契数可能是一个很好的例子。仅供参考,斐波那契如下(有时从零开始):

    1,1,2,3,5,8,13

    Fn=Fn-1+Fn-2

    F0=1,F1=1,n>=2


如果您向我们展示代码……糟糕的终止条件+深度递归,我们将很乐意为您提供帮助。如果您发布了您试图解决的问题、您当前用于解决问题的代码以及预期结果/输出是什么,这将很有帮助。从抽象意义上讲,情况可能并不糟糕。但是它需要太多的递归调用才能在语言和硬件的限制下自行解决。@user658168,这是你的问题,如果你连解释都懒得解释,那我们为什么还要回答你呢?只是吹毛求疵:图灵机不做递归,它们基本上是迭代的。是的,但是递归在这里只是通过迭代来模拟的。对于这个断言,您应该使用一些递归机器模型(具有无限堆栈)。(毕竟,大多数Java堆栈太小的实际问题可以简单地在迭代版本中转换,使用堆代替。当然,堆也可能受到限制。)+1。另外,我发现在调试环境中放置断点和单步执行代码是调试堆栈溢出异常最有效的方法。@StriplingWarrior:当然;不知道为什么我忘了提那件事。调试为您提供了一个非常详细的执行视图,而我描述的方法提供了一个非常方便、快速的递归过程。将两者结合起来通常是有用的。
function sum(n){
  Stack stack
  while(n > 0){
    stack.push(n)
    n--
  }
  localSum = 0
  while(stack not empty){
    localSum += stack.pop()
  }
  return localSum
}
public static int factorial( int n ){
    if( n < n ) // Bad termination condition
        return 1;
    else
        return n*factorial(n+1); // Bad recursion call
}