简体   繁体   中英

Trouble Understanding Recursion

Ok, so I have a program:

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

It's output is 5,4,3,2,1,1,2,3,4,5. My question is, why/how does the second println(n) statement get executed? I thought that the function call would completely cut it off, instead it acted in a way that baffles me. This isn't homework or anything, I just really am having a hard time understanding how recursion works.

All method calls return to the same place once they are done.

By effectively chaining them you get

 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)

Does that make sense?

When your test method terminates, it'll resume in the same place it was in the stack frame above.

For example, if I had some code:

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

...you'd expect both printlns inside main to run, since myFunc terminates/doesn't enter an endless loop.

That's true, even if you're using recursion. Your test method will eventually terminate, so that means that the second println must be executed at some point in time.


In contrast, imagine we had a "recursive" function which never terminates:

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

Because the test2 method never terminates, there's absolutely no way for the second println to execute. It's for this reason why you should always design any recursive function so that it can terminate when some condition is reached.

Concept of stack is very important if we were to understand a recursion. Stack is A LIFO data structure. Remember whenever a method call happens the current state is pushed into the stack (Current state involves the values of local variables , address of next executable statement etc). Now lets see your problem.

First this happens,

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

Now the condition if(n>0) fails now returning phase of recursion happens ie, the control goes back to the state from which the call was made, and remember all the states were stored in stack and also remember stack is LIFO so now:

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

Now all the calls are completed and the control goes back to main.

Please look your code:

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

To assume that your expected result should be "54321", your problem is your second

System.out.println(n);

The first part of your test-method does exactly what you want it to do:

if (n > 0) {
    System.out.println(n);
    test(n-1);
// System.out.println(n); 
}

The result would be "54321" - fantastic! But what happens, because of the second println-method at the end of your test-method, is that you are stacking you output actually (as Crazy Programmer already showed us really precisley). In other words: you don't need the second println-method at all to reach your goal! And that's the wonderful thing about recursion: it "breaks" when calling test() again, leaving your second println-method "not executed by now" and starts the whole process again.

What you propably don't see is, that by using

if (n > 0)

you are verifying that n is greater than 0 (so at least 1), while (at the same time) this is your break condition too! So what your method actually has to do is:

  1. check, if n is greater than 0,
  2. print the value of n, and (at last)
  3. call test-method again (with n-1)

If n reaches 0, the whole "method-stacking" dissolves itself (have a look at Niels' solution) and wont return you any further n-values. Got it?

The method is still existing after the recursive call to itself. Once those calls are dealt with, the method will come back to execute the remaining lines of code.

Have a look at this : 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);
        }
    }

Probably it will help to clarify things.

I think you should trace code then you will get solution.

your code trace something like this. try to debug this lines this might help you.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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