繁体   English   中英

理解递归的麻烦

[英]Trouble Understanding Recursion

好的,所以我有一个程序:

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)语句? 我认为函数调用会完全切断它,而是以令我困惑的方式行事。 这不是家庭作业或任何事情,我真的很难理解递归是如何工作的。

一旦完成,所有方法调用都会返回到同一个地方。

通过有效地链接他们,你得到

 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)

那有意义吗?

当您的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绝对没有办法执行。 这就是为什么你应该总是设计任何递归函数,以便它可以在达到某些条件时终止。

如果我们要理解递归, 堆栈的概念是非常重要的。 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

现在条件if(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); 

现在所有的呼叫都已完成,控制权将恢复为主要状态。

请查看您的代码:

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

假设您的预期结果应为“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),而(同时)这也是你的休息条件! 那么你的方法实际上要做的是:

  1. 检查,如果n大于0,
  2. 打印n的值,并且(最后)
  3. 再次呼叫测试方法(用n-1)

如果n达到0,整个“方法堆叠”会自行消解(看看Niels的解决方案)并且不会再返回任何n值。 得到它了?

在递归调用自身之后,该方法仍然存在。 一旦处理完这些调用,该方法将返回执行剩余的代码行。

看看这个: http//ideone.com/zWqP8h

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

可能有助于澄清事情。

我认为你应该跟踪代码然后你会得到解决方案。

你的代码跟踪这样的东西。 尝试调试此行可能会对您有所帮助。

//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.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM