1

我做了一个计算整数位数之和的函数。为了使代码更短,我在 if 语句中添加了注释,以查看它是否仍然有效,因此我可以将其删除,但我得到一个StackOverflowError,为什么?这是我的代码:

public static int sumDigits(int n) {


    //if(n%10==n){ return n;}

      return n%10+sumDigits(n/10);

    }

public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println(sumDigits(12611));

}
4

9 回答 9

4

它永远不会返回,只会越来越深地递归。

您确实有一个 return 语句,但在返回之前需要计算n%10+sumDigits(n/10)涉及无限递归的表达式的值。

注意:每次从自身调用函数时,都会将函数的上下文(局部变量)添加到堆栈顶部。堆栈的大小是有限的。最终你达到了那个大小,而 StackOverflowError 是在这种情况下引发的错误。

于 2013-05-06T13:17:03.673 回答
3

那是因为没有停止条款。你将永远调用sumDigits

于 2013-05-06T13:16:33.470 回答
3

递归函数可以定义为将操作表示为对更接近端点的值的操作的函数。

因此,每个递归函数在某个时候都需要一个结束条件,否则它将无限递归(或者更准确地说,直到你破坏你的堆栈)。

“数字总和”递归方法(对于 的非负值n)的基本定义是:

def sumOfDigits (n):
    if n < 10:
        return n
    return (n % 10) + sumOfDigits (n / 10) # assumes integer division.

第一点,即结束条件,非常重要,您似乎出于某种原因将您的注释掉了。

于 2013-05-06T13:21:33.553 回答
2

如果删除该行,则递归不再具有基本情况,这意味着它永远不会返回。

于 2013-05-06T13:16:31.473 回答
2

每当为程序分配的内存中的地址堆栈不能存储任何新地址时,就会发生堆栈溢出错误。

因此,当您递归调用sumDigits()系统时,请继续以 LIFO 方式保存最后一次跟踪。这样系统就很容易回到以前的地址,这是递归所必须的。

如果您无限递归或超出内存限制,您将遭受 stackOverflow 错误。

于 2013-05-06T13:23:10.553 回答
2

您注释掉的语句是此递归函数的基本情况。如果没有基本情况,此函数将无限循环。


当您在 main 方法中计算示例时,您会得到:
sumDigits(12611)
= 1 + sumDigits(1261)
= 1 + ( 1 + sumDigits(126))
= 1 + ( 1 + (6 + sumDigits(12)))
= 1 + ( 1 + (6 + ( 2 + sumDigits(1))))
= 1 + ( 1 + (6 + ( 2 + ( 1 + sumDigits(0))))) //此时注释掉if 语句将返回
= 1 + ( 1 + (6 + ( 2 + ( 1 + ( 0 + sumDigits(0))))))
= 1 + ( 1 + (6 + ( 2 + ( 1 + ( 0 + ( 0 + sumDigits(0)))))))
...

此时程序陷入无限循环。当 n 为 1 时,注释掉的语句将返回,从而防止了这种情况。

于 2013-05-06T13:33:19.280 回答
1

因为您是sumDigits()从自身调用,并且应该导致您从无限递归返回的代码已被注释掉。取消注释行if(n%10==n){ return n;}

于 2013-05-06T13:17:01.647 回答
1

您的递归没有终止条件。否则,你一遍又一遍地调用递归函数,最终stack会溢出

于 2013-05-06T13:18:02.810 回答
0

取消注释您的停止条件。

于 2013-05-06T13:18:33.670 回答