递归返回值

时间:2016-02-23 22:57:45

标签: java recursion

过去几周我一直在学习java的递归。虽然我对实际发生的事情感到有些困惑,但我已经逐步完成了这个方法(使用eclipse)。我看到的是else语句使变量" n"递减直到1然后最终访问if语句(如预期的那样)。这是我迷路的地方。在这一点上,我看到" n"变量从1增加到5(调用方法时我的输入为5),重复访问else语句返回。

基本上我的问题是为什么在&#34之后返回1;如果"语句执行跳转到else的代码返回?另外,为什么在执行此操作后执行5次而不是跳出方法?

我知道这是递归的一个基本概念,但它显然完全失去了我

public static long getFactorial(long n) {

    if (n == 1){
        return 1;
    }
    else {
        return n * getFactorial(n-1);
    }

3 个答案:

答案 0 :(得分:3)

代码跳转到"否则返回"从以前的执行。在为n=1返回1之后,带有n=2的函数调用会立即返回2 * 1 - 这就是突然跳转的原因。您正在混淆多个单独的方法调用。

invocation(2)
|
invokes ->      invocation(1)
|               |
|               returns 1
returns 2 * 1

使用n=2调用后返回一个值,使用n=3调用会立即使用它返回结果 - 依此类推。这就是为什么有多个" else返回":

inv(5)
5 * inv(4)
5 * 4 * inv(3)
5 * 4 * 3 * inv(2)
5 * 4 * 3 * 2 * inv(1)
5 * 4 * 3 * 2 * 1    [return inv(1)]
5 * 4 * 3 * 2        [return inv(2)]
5 * 4 * 6            [return inv(3)]
5 * 24               [return inv(4)]
120                  [return inv(5)]

答案 1 :(得分:0)

初始调用将getFactorial(3)这将解析为3* getFactorial(3-1)并继续,因此通用调用堆栈将是。

3 * getFactorial(3-1)
3 * (2 * getFactorial(2-1))
3 * (2 * 1) // if statement is true and returning one and executing the recursion popping elements of the stack
3 * 2
6

元素保留在堆栈中,如果计算时间很长,则容易受到stackoverflow异常的影响。因此,在Java中进行循环是一种更好的做法。这是Scala的作用,当递归递归完成递归时,它会在编译时将其转换为循环。因此,通常没有很好的理由去做,特别是在面向对象的编程语言中,它没有针对递归进行优化。

答案 2 :(得分:0)

将Eclipse放在一边,使用笔和纸完成代码执行。每次调用方法时使用新工作表,将其放在上一工作表的顶部。当您到达“return”时,丢弃顶部工作表并将您返回的值放入调用语句中。这是Java调用堆栈的准确表示。

所以:从主要调用get factorial(2)开始。

将整个方法源代码写在一张纸上。逐步完成代码。 n = 2.是n == 1?不,所以跳到else

现在您拨打getFactorial(n-1)来电。由于n是2,那是getFactorial(1)。这是一个新的调用,所以标记你要离开当前执行的位置,然后在堆栈顶部放一张新纸,并在其上写入方法源。

再次单步执行代码,这次是n == 1.在if语句中,您到达return 1。所以,丢弃顶层纸。它已经完成了它的工作,然后返回1.继续踩着现在最顶层的东西。请记住,此工作表有自己的n,即2.当前步骤是返回n乘以刚刚丢弃的工作表的返回值。因此,返回2 * 1,丢弃当前工作表,由于您没有更多工作表,您将返回原始来电者并获得答案。

使用较大的第一个n重复此练习,并且应该清楚发生了什么。

回到Eclipse中,可以在调试器中查看堆栈。堆栈跟踪彼此调用的方法链,即使不涉及递归也是如此。在将你学到的东西应用到递归之前,可能值得研究另一个暂停程序的堆栈来理解这一点。