Java简单的递归函数解释

时间:2016-01-30 16:21:33

标签: java recursion

所以,这是代码:

  package rekurzija;


public class exkurzija {

    public static void main(String[] args) {

    myMethod(4);

    }
    static void myMethod( int counter)
    {
        if(counter == 0)
            return;
        else
               {
               System.out.println("hello" + counter);
               myMethod(--counter);
               System.out.println(""+counter);
               return;
               }
        } 

}

这是输出:

hello4
hello3
hello2
hello1
0
1
2
3

现在,我试图理解这一点,尝试谷歌搜索这个问题,但没有用。我无法找到与此有关的协议。 所以更具体一点,我理解为什么会发生这种情况:

hello4
hello3
hello2
hello1

但我绝对不明白为什么会这样:

0
1
2
3

如果有人能解释为什么最终它会增加,为什么它不会继续减少,我将非常感激?

3 个答案:

答案 0 :(得分:4)

以下是递归的顺序。每个级别的缩进表示更深的呼叫。

myMethod(4)
 . counter is 4
 . print "hello4"
 . counter-- and is now 3
 . myMethod(3)
 . . counter is 3
 . . print "hello3"
 . . counter-- and is now 2
 . . myMethod(2)
 . . . counter is 2
 . . . print "hello2"
 . . . counter -- and is now 1
 . . . myMethod(1)
 . . . . counter is 1
 . . . . print "hello1"
 . . . . counter-- and is now 0
 . . . . myMethod(0)
 . . . . . counter is 0
 . . . . . return
 . . . . print counter "0"
 . . . . return
 . . . print counter "1"
 . . . return
 . . print counter "2"
 . . return
 . print counter "3"
 . return

要回答OP的问题,最后由于代码行而打印0/1/2/3:

System.out.println(""+counter);

请注意,这会在每个递归级别调用,这由计数器指示。

答案 1 :(得分:3)

您的递归电话:

myMethod(--counter);

...发生在代码中,要在方法中执行。因此,挂起的方法然后被放入堆栈并等待递归调用完成,此时方法然后以与它们被添加到堆栈的方式相反的顺序完成。因此,第一次通过该方法检查零值并且没有发现它们打印“hello4”然后该方法的实例进入堆栈,而下一个实例从myMethod(--counter);行调用。该实例的值与3相同,然后是2,然后是1.此时检测到零值并且递归停止,然后代码开始回调您已经推入堆栈的方法,因为它们不完整,即:他们还没有遇到任何返回指令,他们坐在那里等着指示:

System.out.println(""+counter);

然后你的方法遇到最后一条返回指令并完成。 因此,如果您打算将“hello4”等打印而不是打印底部,那么myMethod(--counter);所示的行应为:

return myMethod(--counter);

答案 2 :(得分:2)

理解递归的方法是展开它。

static void myMethod( int counter) {
    if(counter == 0) {
        return;
    }
    else {
        System.out.println("hello" + counter);
        myMethod(--counter);
        System.out.println(""+counter);
        return;
    }
}

以上是您修改​​格式的原始功能。在进一步讨论之前,我想稍微简化它。

static void myMethod(int counter) {
    if(counter > 0) {
        System.out.println("hello" + counter);
        counter -= 1;
        myMethod(counter);
        System.out.println(""+counter);
    }
}

逻辑被简化了,但是这个方法完成了所有相同的事情(除了它确实允许自己必须包含负数,如果给出负输入)。

我已经对此进行了简化,因为我想在原始参数为2的情况下解开它。我们将打开整个堆栈,并按照执行的顺序轻松跟踪代码。发生了什么事。

int counter2 = 2; // assume we called your method with an argument of 2
if(counter2 > 0) { // it is, it's 2
    System.out.println("hello"+counter2); // "hello2"
    counter2 -= 1;  // counter2 is now 1

    // enter recursive call
    int counter1 = counter2; // the recursive call has a different scope
    if(counter1 > 0) { // it is, it's 1
        System.out.println("hello"+ counter1); // "hello1"
        counter1 -= 1; // counter1 is now 0

        // enter recursive call
        int counter0 = counter1; // the recursive call has a different scope
        if(count0 > 0) { // it is not, do nothing
        }
        // exit recursive call

        System.out.println(""+counter1); // we're still in one layer of recursion, this prints 0
    }
    // exit recursive call

    System.out.println(""+counter2); // this prints 1
}
// exit function

这种模式应该很清楚。以4作为起始参数,模式只有两层深度。

这里要记住两件重要的事情。

  1. 每个递归层都有自己的范围和自己的变量集。
  2. 在构建并返回整个递归堆栈之后,递归调用之后存在的任何代码
  3. 你方法的要点是:

    1. 打印"hello"+counter
    2. 从柜台减去一个。
    3. 运行myMethod
    4. 打印counter
    5. 如果我们取消第三步,我们就不再做任何递归的事了。因此,我们会更直观地看到更符合逻辑的东西。但是对于每一层递归,我们必须用步骤1到步骤4替换步骤3.因此对于一层递归,步骤的顺序变为:

      • 打印"hello"+counter
      • 从柜台减去一个。
        1. 打印"hello"+counter
        2. 从柜台减去一个。
        3. 运行myMethod
        4. 打印counter
      • 打印counter

      要添加另一个图层,我们再次将步骤3替换为步骤1-4。

      • 打印"hello"+counter
      • 从柜台减去一个。
        • 打印"hello"+counter
        • 从柜台减去一个。
          1. 打印"hello"+counter
          2. 从柜台减去一个。
          3. 运行myMethod
          4. 打印counter
        • 打印counter
      • 打印counter

      这个模式重复变得越来越嵌套,直到你遇到你的基本情况(counter == 0)或最终遭遇堆栈溢出异常。

      当我们遇到基本案例时,第3步看起来像这样:

      • 打印"hello"+counter
      • 从柜台减去一个。
        • 打印"hello"+counter
        • 从柜台减去一个。
          1. 打印"hello"+counter
          2. 从柜台减去一个。
          3. 什么都不做。
          4. 打印counter
        • 打印counter
      • 打印counter