【问题标题】:Java simple recursive function explanation [closed]Java简单递归函数解释
【发布时间】:2016-05-08 08:11:28
【问题描述】:

所以,这是代码:

  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

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

【问题讨论】:

  • 为 myMethod(2) 手动追踪它,应该很清楚。
  • @JamesKPolk 我试过了,仍然 - 我不明白。能具体点吗?
  • 嗯,首先减去计数器,然后然后输出数字...
  • 宽泛地让我解释一下,这样您就可以确定发生了什么,但基本上第一个退出递归调用的是位于 0 的那个,然后另一个退出之后彼此...
  • 这类疑问通常可以使用IDE(如eclipse)和断点来解决,这样你就可以逐步处理你的代码......

标签: java recursion


【解决方案1】:

这是递归执行的顺序。每一级缩进表示更深层次的调用。

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);

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

【讨论】:

  • 我知道这一点。但问题是为什么它会增加?为什么不只显示:0 0 0 0,还是继续递减?
  • 它没有增加。每次调用 myMethod 时,它都会在堆栈上获得一个新计数器。让我们看一下对 myMethod 的单个调用,例如 myMethod(2)。看上面的痕迹。圈出带有三个点“......”的线条在他们面前。 (你应该找到 6 行。)在三点级别打印出什么? Hello2 和 1,但在不同的时间。在 Hello2 和 1 之间,它也会打印 Hello1 和 0,但在四点级别。
  • 另一种解释方式是,在三点级别,创建一个新计数器,初始化为 2 并递减为 1。在四点级别,创建一个新计数器初始化为 1 并递减为 0。
【解决方案2】:

你的递归调用:

myMethod(--counter);

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

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

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

return myMethod(--counter);

【讨论】:

  • this part "THEN 你的方法遇到最后一个返回指令并且完成。所以如果你打算打印 "hello4" 等而不是底部部分,那么 myMethod(-- counter); 应该是:return myMethod(--counter);"是不正确的。给出一个错误。
  • 是的,你是对的:当你这样做时,Java 不喜欢它(c++ 本来可以的)。实际上,我会提供一些建议:首先,“else”语句是不必要的。如果满足零条件,则 return 语句阻止执行后续代码,如果不满足,则代码无论如何都会落入 System.Out.println。因此,如果您不想打印 0、1、2、3,请创建 myMethod(--counter);方法的最后一行。不过它会放在堆栈上,这就是为什么我想在该行中包含一个 return。
【解决方案3】:

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

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. 在递归调用执行整个递归堆栈构建并返回之后存在的任何代码。

你的方法的要点是这样的:

  1. 打印"hello"+counter
  2. 从计数器中减一。
  3. 运行myMethod
  4. 打印counter

如果我们去掉第三步,我们就不再做任何递归了。所以我们会看到一些更直观更符合逻辑的东西。但是对于每一层递归,我们必须将步骤 3 替换为步骤 1 到 4。所以对于一层递归,步骤的顺序变为:

  • 打印"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

并且这种模式重复变得越来越嵌套,直到您遇到基本情况(计数器 == 0)或最终遇到堆栈溢出异常。

当我们达到基本情况时,步骤 3 如下所示:

  • 打印"hello"+counter
  • 从计数器中减一。
    • 打印"hello"+counter
    • 从计数器中减一。
      1. 打印"hello"+counter
      2. 从计数器中减一。
      3. 什么都不做。
      4. 打印counter
    • 打印counter
  • 打印counter

【讨论】:

  • 我知道这一点。但问题是为什么它会增加?为什么不只显示:0 0 0 0,还是继续递减?
  • 你看过解开的代码示例了吗?如果你看不懂我给你看的未解开的代码示例,恐怕我不知道如何帮助你......
  • 您还没有解释为什么它会增加。您已经解释了它是如何工作的,仅此而已。我的问题很简单:为什么会增加?
  • 浏览解开的代码示例并阅读那里的 cmets。解释完全在那里。剩下的就是阅读和理解。请注意,我还使用 counter2counter1counter0 等名称来调用计数器,以便更清楚地说明我们正在处理不同的变量、不同级别的范围。解开的代码示例按照它实际执行的确切顺序放置代码。
猜你喜欢
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-27
  • 2021-11-28
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
相关资源
最近更新 更多