【问题标题】:how recursive function works level by level?递归函数如何逐级工作?
【发布时间】:2020-02-11 21:30:03
【问题描述】:

我很难理解递归是如何工作的,我已经为此苦苦挣扎了一段时间!任何人都可以帮助我吗?我真的很感激,下面是代码:

public int recur(int m) {   
    if(m == 0) {
        return 2;
    }
    int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1;
    System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;
}

当我们将 3 传递给函数时,输出将是:

The K before is0 m is:3
The K before is0 m is:2
The K before is0 m is:1
The K AFTER is3 m is:1
The K AFTER is4 m is:2
The K AFTER is5 m is:3

由于递归调用在两次打印之间,我猜它的工作方式是函数将:

  1. 在递归调用之前执行代码。
  2. 那么它就不会遍历递归调用下面的代码并停在那里。
  3. 跳回到方法的开头。
  4. 递归调用前的一切都完成后,程序会继续执行递归调用后的代码。

这是正确的概念吗?或者有人能解释一下吗?真的很感激!

【问题讨论】:

  • 不要将其视为“停在那里”,而是尝试将其视为“暂停一段时间,同时运行具有略微不同参数的同一函数的另一个版本”。你并没有把原作抛在脑后,你只是在做其他事情的时候把它推迟一段时间。

标签: java recursion


【解决方案1】:

关于递归,您首先要了解的是,您正在执行相同的方法,但您并没有在其中跳跃。你得到不同的处决。让我们从没有递归的简单开始:

public void a() {
  System.out.println(">> before b()");
  b();
  System.out.println("<< after b()");
}

public void b() {
  System.out.println(">>>> in b() <<<<");
}

当您致电a() 时:

  1. 在 b() 之前打印 >>

  2. 致电b()

  3. 在 b() 中打印 >>> 。

  4. 完成b()的执行。

  5. 返回a()并打印

  6. 完成a()的执行。

因此,当您调用一个方法时,当前的方法会等待调用完成然后继续。对b() 的调用嵌套在a() 中。

在递归的情况下,会发生同样的事情,但您调用的是相同的方法,而不是 不同的 方法。从本质上讲,您会获得执行和等待的方法的不同版本,您不会跳过同一个。因此,通过递归调用,您会得到如下结果:

  1. 您调用recur(3) 并执行该方法。

  2. 它打印is0 m之前的K是:3

  3. 该方法调用recur(2),这是一个递归调用。此时你得到以下状态:

public int recur(int m) {/* m = 2 */
    if(m == 0) {
        return 2;
    }
    int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1; // <-- stop and wait for this to finish
    System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;
}
  1. 现在您获得了方法执行的全新副本。这称为recur(2)

  2. 它打印 is0 m 之前的 K is:2

  3. 该方法调用recur(2),这是一个递归调用。此时你得到以下状态:

public int recur(int m) {/* m = 3 */                             | public int recur(int m) {/* m = 2 */
    if(m == 0) {                                                 |     if(m == 0) {
        return 2;                                                |         return 2;
    }                                                            |     }
    int k = 0;                                                   |     int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; // <-- stop and wait for this to finish
    System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;                                                    |     return k;
}                                                                | }
  1. 现在您获得了方法执行的全新副本。这称为recur(1)

  2. 它打印 is0 m 之前的 K is:1

  3. 该方法调用recur(0),这是一个递归调用。此时你得到以下状态:

public int recur(int m) {/* m = 3 */                             | public int recur(int m) {/* m = 2 */                             | public int recur(int m) {/* m = 1 */
    if(m == 0) {                                                 |     if(m == 0) {                                                 |     if(m == 0) {
        return 2;                                                |         return 2;                                                |         return 2;
    }                                                            |     }                                                            |     }
    int k = 0;                                                   |     int k = 0;                                                   |     int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; // <-- stop and wait for this to finish
    System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;                                                    |     return k;                                                    |     return k;
}                                                                | }                                                                | }
  1. 现在您获得了方法执行的全新副本。这称为recur(0)

  2. 这次执行进入if 语句,因为条件已满足。一切解决之前的最终状态:

public int recur(int m) {/* m = 3 */                             | public int recur(int m) {/* m = 2 */                             | public int recur(int m) {/* m = 1 */                             | public int recur(int m) {/* m = 0 */
    if(m == 0) {                                                 |     if(m == 0) {                                                 |     if(m == 0) {                                                 |     if(m == 0) {
        return 2;                                                |         return 2;                                                |         return 2;                                                |         return 2; // <-- return and finish
    }                                                            |     }                                                            |     }                                                            |     }
    int k = 0;                                                   |     int k = 0;                                                   |     int k = 0;                                                   |     int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1;
    System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;                                                    |     return k;                                                    |     return k;                                                    |     return k;
}                                                                | }                                                                | }                                                                | }
  1. 最后,嵌套调用由内而外解析。

  2. recur(0) 完成。返回2。计算recur(0)+1 的结果最终可以继续并分配结果k。现在陈述:

public int recur(int m) {/* m = 3 */                             | public int recur(int m) {/* m = 2 */                             | public int recur(int m) {/* m = 1 */
    if(m == 0) {                                                 |     if(m == 0) {                                                 |     if(m == 0) {
        return 2;                                                |         return 2;                                                |         return 2;
    }                                                            |     }                                                            |     }
    int k = 0;                                                   |     int k = 0;                                                   |     int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; // <-- recur(m - 1) = 2
    System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;                                                    |     return k;                                                    |     return k;
}                                                                | }                                                                | }
  1. K AFTER is3 m is:1 打印出来。

  2. recur(1) 完成。返回3。计算recur(1)+1 的结果最终可以继续并分配该结果k。现在陈述:

public int recur(int m) {/* m = 3 */                             | public int recur(int m) {/* m = 2 */
    if(m == 0) {                                                 |     if(m == 0) {
        return 2;                                                |         return 2;
    }                                                            |     }
    int k = 0;                                                   |     int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);         |     System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1; /*<-- still waiting for this to finish*/ |     k = recur(m - 1)+1; // <-- recur(m - 1) = 3
    System.out.println("The K AFTER is"+ k+" m is:"+m);          |     System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;                                                    |     return k;
}                                                                | }
  1. K AFTER is4 m is:2 打印出来。

  2. recur(2) 完成。返回4。计算recur(2)+1 的结果最终可以继续并分配结果k。现在陈述:

public int recur(int m) {/* m = 3 */
    if(m == 0) {
        return 2;
    }
    int k = 0;
    System.out.println("The K before is"+ k+" m is:"+m);
    k = recur(m - 1)+1; // <-- recur(m - 1) = 4
    System.out.println("The K AFTER is"+ k+" m is:"+m);
    return k;
}
  1. K AFTER is5 m is:3 打印出来。

  2. recur(3) 的初始调用结束。

因此,从另一个方法启动的对方法的每次调用都会启动嵌套执行。然后执行首先解决内部,然后继续执行外部。每个调用都有自己的状态 - 如果您在调试器中跟随它似乎就像执行移动到方法的开头,但实际上您现在处于与旧的完全不同的执行中一个。

【讨论】:

  • 哇!非常感谢!!你的解释对我来说很清楚!希望这个社区有更多这样的答案!真的很感激!
【解决方案2】:

这有助于我把它想象成从楼梯上跑下来,然后再上楼梯。对于在执行任何操作之前调用自身的方法,我会将其可视化如下:

Start 1
Call 2
    Start 2
    Call 3
        Start 3
        DoSomething 3
        End 3
    DoSomething 2
    End 2
DoSomething 1
End 1

【讨论】:

    猜你喜欢
    • 2012-02-24
    • 1970-01-01
    • 2011-03-29
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 2019-03-05
    • 2012-02-09
    相关资源
    最近更新 更多