【问题标题】:Order of recursion method's calls递归方法的调用顺序
【发布时间】:2012-05-26 19:04:33
【问题描述】:

我很好奇递归在 jvm 中是如何工作的。遵循示例。首先计算给定数的阶乘。

public class Factorial {

public int factorial(int n) {
    System.out.println("Factorial: " + n);
    if ( n < 2) {
        return 1;
    } 

    return n * factorial(n - 1);
}

执行以下测试

    @Test
public void test_factorial() {
    Factorial fact = new Factorial();
    System.out.println(fact.factorial(3));
}

展示

3
2
1

看起来很明显,方法调用被放入堆栈,执行到达 n == 1 并返回。 现在,我尝试计算斐波那契数。

public int fibo(String name, int n) {
    System.out.println("fibo: " + name +  " " + n);
    if (n < 2 ) {
        return n;
    }
    return fibo ("left", n - 1) + fibo ("right", n - 2);
}

执行测试

@Test
public void test_fibonacci() {
    Fibo fibo = new Fibo();

    assertEquals(8, fibo.fibo("start",6));

}

打印下面的内容

fibo: start 6
fibo: left 5
fibo: left 4
fibo: left 3
fibo: left 2
fibo: left 1
fibo: right 0
fibo: right 1
fibo: right 2
fibo: left 1
fibo: right 0
fibo: right 3
fibo: left 2
fibo: left 1
fibo: right 0
fibo: right 1
fibo: right 4
fibo: left 3
fibo: left 2
fibo: left 1
fibo: right 0
fibo: right 1
fibo: right 2
fibo: left 1
fibo: right 0

我的问题是这个例子中调用方法并入栈的规则是什么?

【问题讨论】:

  • 在现实世界中,避免使用斐波那契风格的递归程序,因为它们会导致方法调用呈指数级增长。
  • 给自己画一个函数调用树,这样可以使行为非常清晰。总结一下:函数的所有参数都执行完后调用,函数的参数是从左到右执行的。

标签: java recursion


【解决方案1】:

语句在 Java 中是从左到右计算的。以下是对较小输入的斐波那契函数的简单分解:

fib.fibo("start",3)

被调用,打印“start: 3”。它试图评估

(1) fibo("left", 2) + fibo("right", 1)

由于评估是 LTR,这意味着

(2) fibo("left", 2)

首先得到评估。我们创建了一个新的堆栈帧,语句 (1) 正在等待它的返回。调用 (2) 打印“left: 2”并尝试评估

(3) fibo("left", 1) + fibo("right", 0)

同样,LTR 评估意味着我们评估

(4) fibo("left", 1)

首先。同样,新的堆栈帧 (3) 等待 (4) 的响应。调用 (4) 打印“left: 1”并返回 1。堆栈帧弹出,并且 (3) 现在继续其评估,调用

(5) fibo("right", 0)

这将打印“right: 0”并返回 0。(2) 现在能够完成其评估并返回 1+0 = 1。语句 (1) 终于完成了对 fibo("left", 2) 的评估并可以继续评估 @ 987654328@同上。

我希望这有助于澄清!

【讨论】:

  • 因此方法调用将不是对称的(如建议的“alaster”)。从某种意义上说,大多数“左”电话会经常被调用? (我不知道这个问题是否有意义:))
  • 不,每次调用fibo 都将返回1 调用fibo 两次——一次用于左侧,一次用于右侧。即使在 alaster 的示例树中,您也可以看到进行了相同数量的左右调用(各 3 个)。
【解决方案2】:

有什么问题? 你在运行这段代码时从左到右和从右到左改变(left1里面有right2):

             start
    left1           right1 
left2  right2    left3  right3 

您先拨打left1,然后拨打left2。然后返回left1,但不打印,然后调用right2。然后返回两次,你又回到了start。之后你打电话给right1,这将是类推。

所以你有: 开始-左1-左2-右2-右1-左3-右3

【讨论】:

    猜你喜欢
    • 2019-12-20
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 2014-03-02
    • 2021-11-07
    • 2016-03-02
    相关资源
    最近更新 更多