我很难低估递归的工作方式,我已经为此苦苦挣扎了一段时间!有人可以帮我吗?我真的很感激,这里是示例代码:
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
由于递归调用是在两次打印之间进行的,所以我想函数的工作方式将是:
这是正确的概念吗?或有人可以解释吗?真的很感谢!
答案 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()
时,将会:
在b()之前打印>>。
致电b()
。
在b()<<<<< / strong>中打印>>>>。
完成b()
的执行。
返回a()
并在b()之后打印 <<。
完成a()
的执行。
因此,当您调用一种方法时,当前方法会等待调用完成,然后继续。对b()
的调用嵌套在a()
中。
在递归的情况下,会发生相同的事情,但是您调用的是相同的方法,而不是不同的方法。本质上,您得到的方法的不同版本 都在执行和等待,您不会跳到同一个方法。因此,通过递归调用,您将得到以下信息:
您调用recur(3)
并执行该方法。
它打印 0m之前的K是: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;
}
现在您将获得方法执行的全新副本。这称为recur(2)
。
它打印 0m之前的K是:2
该方法调用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;
} | }
现在您将获得方法执行的全新副本。这称为recur(1)
。
它打印 0m之前的K为:1
该方法调用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;
} | } | }
现在您将获得方法执行的全新副本。这称为recur(0)
。
这一次执行是在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;
} | } | } | }
最后,嵌套调用从内而外得到解决。
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;
} | } | }
打印的K AFTER是3 m:1 。
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;
} | }
打印出的K AFTER是4 m: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;
}
打印出的K AFTER是5 m:3 。
对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