递归函数如何逐级工作?

时间:2020-02-11 21:30:03

标签: java recursion

我很难低估递归的工作方式,我已经为此苦苦挣扎了一段时间!有人可以帮我吗?我真的很感激,这里是示例代码:

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. 在完成递归调用之前的所有操作之后,程序将在递归调用之后继续执行代码。

这是正确的概念吗?或有人可以解释吗?真的很感谢!

2 个答案:

答案 0 :(得分: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()<<<<< / strong>中打印>>>>。

  4. 完成b()的执行。

  5. 返回a()并在b()之后打印 <<。

  6. 完成a()的执行。

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

在递归的情况下,会发生相同的事情,但是您调用的是相同的方法,而不是不同的方法。本质上,您得到的方法的不同版本 都在执行和等待,您不会跳到同一个方法。因此,通过递归调用,您将得到以下信息:

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

  2. 它打印 0m之前的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. 它打印 0m之前的K是: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. 它打印 0m之前的K为: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是3 m: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是4 m: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是5 m:3

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

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

答案 1 :(得分:0)

它可以帮助我将其想象成是从楼梯上跑下来,然后又回到楼梯上。对于在执行任何操作之前调用其自身的方法,我将其可视化如下:

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