好的,我有一个程序:
public class Rec {
public static void main(String[] args) {
test(5);
}
static void test(int n) {
if (n > 0) {
System.out.println(n);
test(n-1);
System.out.println(n);
}
}
它的输出是5,4,3,2,1,1,2,3,4,5。我的问题是,为什么/如何执行第二个println(n)语句?我认为函数调用会完全切断它,而是以令我困惑的方式行事。这不是家庭作业或任何事情,我真的很难理解递归的工作原理。
答案 0 :(得分:5)
所有方法调用一旦完成就会返回到同一个地方。
通过有效地链接它们,你得到了
System.out.println(5)
System.out.println(4)
System.out.println(3)
System.out.println(2)
system.out.println(1)
// If is not true now.
System.out.println(1)
System.out.println(2)
System.out.println(3)
System.out.println(4)
System.out.println(5)
这有意义吗?
答案 1 :(得分:3)
当您的test
方法终止时,它将恢复到上面堆栈框架中的相同位置。
例如,如果我有一些代码:
public class Test {
public static void main(String[] args) {
System.out.println("A");
myFunc();
System.out.println("B");
}
public static void myFunc() {
System.out.println("Do something here");
}
}
...你希望main
内的两个printlns都能运行,因为myFunc
终止/不会进入无限循环。
即使您正在使用递归,也是如此。您的test
方法最终将终止,这意味着必须在某个时间点执行第二个println。
相比之下,想象一下我们有一个永远不会终止的“递归”功能:
public class Test {
public static void main(String[] args) {
test2(5)
}
public static void test2(int n) {
System.out.println("A " + n);
test(n - 1);
System.out.println("B " + n);
}
}
因为test2
方法永远不会终止,所以第二个println绝对无法执行。这就是为什么你应该总是设计任何递归函数,以便它可以在达到某些条件时终止。
答案 2 :(得分:1)
如果我们要了解递归,堆栈的概念非常重要。 Stack是一个 LIFO 数据结构。记住每当方法调用发生时,当前状态被推入堆栈(当前状态涉及局部变量的值,下一个可执行语句的地址等)。现在让我们看看你的问题。
首先发生这种情况,
System.out.println(5);
test(n-1); // method call is happening so store state to stack !!!
//stack contents: n=5 and address of next statement
System.out.println(4);
test(n-1);//another state added to stack : n =4
System.out.println(3);
test(n-1);//another state added to stack: n = 3
System.out.println(2);
test(n-1);//another state added to stack : n = 2
System.out.println(1);
test(n-1);//another state added to stack : n = 1
现在条件如果(n> 0)失败,现在返回递归阶段,即控件返回到进行调用的状态,并记住所有状态都存储在堆栈并且还记得堆栈是LIFO所以现在:
// n = 1 first state in stack
System.out.println(1);
//n = 2 second state stored in stack
System.out.println(2);
//n = 3 third state stored in stack
System.out.println(3);
//n = 4 fourth state stored in the stack
System.out.println(4);
//n = 5 last state stored in stack
System.out.println(5);
现在所有的调用都已完成,控件将返回main。
请查看您的代码:
static void test(int n) {
if (n > 0) {
System.out.println(n);
test(n-1);// this makes the new call to method test() and causes the state to be stored in the stack
System.out.println(n);// this statement doesn't execute until the recursive call made to test() doesn't return .
}
HTH:)
答案 3 :(得分:1)
假设您的预期结果应为“54321”,那么您的问题就是您的第二个
System.out.println(n);
测试方法的第一部分完全符合您的要求:
if (n > 0) {
System.out.println(n);
test(n-1);
// System.out.println(n);
}
结果将是“54321” - 太棒了! 但是,由于测试方法结束时的第二个println方法,实际上是在堆叠输出(因为Crazy Programmer已经向我们展示了真正的精确度)。换句话说:你根本不需要第二个println方法来实现你的目标!这是关于递归的奇妙之处:它在再次调用test()时“中断”,让你的第二个println方法“暂时不执行”并再次启动整个过程。
您可能看不到的是,使用
if (n > 0)
您正在验证n大于0(至少为1),而(同时)这也是您的休息条件!那么你的方法实际上要做的是:
如果n达到0,整个“方法堆叠”会自行消解(看看Niels的解决方案)并且不会再返回任何n值。知道了吗?
答案 4 :(得分:0)
在递归调用自身之后,该方法仍然存在。一旦处理完这些调用,该方法将返回执行剩余的代码行。
public static void main(String[] args) {
test(5);
}
static void test(int n) {
if (n > 0) {
System.out.println("First step :" + n);
test(n-1);
System.out.println("Second step :" + n);
}
}
可能有助于澄清事情。
答案 5 :(得分:0)
我认为你应该跟踪代码然后你会得到解决方案。
你的代码跟踪这样的东西。尝试调试这一行可能会对你有帮助。
//for n = 5
void test(int n) {
if (n > 0) {
System.out.println(n);
test(n-1);----->// call of same function
//for n = 4
void test(int n) {
if (n > 0) {
System.out.println(n);
test(n-1);----->
//for n = 3
void test(int n) {
if (n > 0) {
System.out.println(n);
test(n-1);---->
//for n = 2
void test(int n) {
if (n > 0) {
System.out.println(n);
test(n-1);---->
//for n = 1
void test(int n) {
if (n > 0) {
System.out.println(n);
test(n-1); ---->
//for n = 0
void test(int n) {
if (n > 0) {//not satisfy
System.out.println(n);
test(n-1);
System.out.println(n);
}
// Till hear you were right but next things you missed.
}//again resume of n = 1
System.out.println(n);
}
}//again resume of n = 2
System.out.println(n);
}
}//again resume of n = 3
System.out.println(n);
}
}//again resume of n = 4
System.out.println(n);
}
}//again resume of n = 5
System.out.println(n);
}
}//Finish recursion.