Videos
Hi all.. I am having quite a lot of difficulty with recursion. For me it is what is happening internally at each step, what is being returned, what the internal stack looks like.. I understand the basics, the base case, like the Fibonacci sequence. Intellectually I understand depth first searches .. but I simply do not understand what is going on under the hood. I cannot make the connection between what visually is supposed to be happening, vs how the algorithm works.
This towers of Hanoi explanation should be more than sufficient, and yet, it simply leaves me overwhelmed.
I am specifically asking for a tutorial in Java - Thank you.
A recursive function is a function that calls itself until it reaches a return statement, that stops it from recalling itself. Take your example, the Factorial function. Factorial is a mathematical function that returns the number multiplied by itself - 1 multiplied by itself - 2, ... multiplied by 1, example: factorial of 5 = 5! = 5x4x3x2x1 = 120. it is also equal to itself multiplied by the factorial of itself -1, which is: 5! = 5x4! Take into consideration that 0! = 1. to represent this in a Java code, you need a loop that multiplies the numbers starting from 1, and going till the number you are calculating its factorial. Further more, explaining your code, let us calculate Factorial(5): Factorial() returns an integer.
Initial Call from main(): 5 != 0, then skip the condition (n == 0); t = Factorial(5-1) = Factorial(4);
Second call from Factorial(4): 4 != 0, then skip the condition (n == 0); t = Factorial(4-1) = Factorial(3);
Third call from Factorial(3): 3 != 0, then skip the condition (n == 0); t = Factorial(3-1) = Factorial(2);
Fourth call from Factorial(2): 2 != 0, then skip the condition (n == 0); t = Factorial(2-1) = Factorial(1);
Fifth call from Factorial(1): 1 != 0, then skip the condition (n == 0); t = Factorial(1-1) = Factorial(0);
Sixth call from Factorial(0): 0 == 0, then return value 1;
First return, 1, to Fifth call (Factorial(1)): return n*t = return 1*1 = return value 1;
Second return, 1, to Fourth call (Factorial(2)): return n*t = return 2*1 = return value 2;
Third return, 2, to third call (Factorial(3)): return n*t = return 3*2 = return value 6;
Second return, 6, to second call (Factorial(4)): return n*t = return 4*6 = return value 24;
Second return, 24, to First call (Factorial(5)): return n*t = return 5*24 = return value 120;
Second return, 120, to Initial call (from main()): print(120);
Hope this helps you understand recursion.
When a call is made to another method, a stack frame is created to hold the state of the current method and it is pushed onto the stack. This is regardless of a method calling itself or another method.
When the call returns, the stack frame is popped of the stack, the state of the method is restored and execution continues in the calling method.
Recursion is when a method (directly or indirectly) calls itself. The general form of a recursive method is:
- If a parameter meets a terminating condition, return (usually a result)
- Else adjust parameters for the next iteration and call self
The code your teacher wrote has some style issues. It would be clearer if written like this:
static int factorial(int n) {
if (n == 0) {
return 1;
}
return n * factorial(n - 1);
}
Eradicating the unnecessary variable t and redundant else (there is no "else" when the "if" returns - there is merely continuation of execution)
I would write it like this, eliminating the if altogether:
static int factorial(int n) {
return n == 0 ? 1 : n * factorial(n - 1);
}
In recursion the order of the calls is very important! You can understand better your own example when you unroll it. It will look like this:
// step 1
// flowerInVase is greater than 7, so the first thing to do is call the function again!
// Note that the System.out.println is NOT yet reached because of the execution of the function!
// call emptyVse(7 - 1), the *stack* has *remembered* to the current value of *floweInVase* => 7
emptyVase(7);
// step 2
emptyVase(6);
// condition is *true* yet again, so the same rules as above apply
// current *remembered* value of `floweInVase` is 6
// step 3
emptyVase(5);
// and so on ... until `flowerInVase` is 0 ... now ...
Now the stack looks like this:
emptyVase(7)
emptyVase(6)
emptyVase(5)
emptyVase(4)
emptyVase(3)
emptyVase(2)
emptyVase(1)
emptyVase(0)
-> nothing to do, recursion is stopped.
-> so go back to previous
-> *stack frame* which is 1
System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
System.out.println(5);
System.out.println(6);
System.out.println(7);
In stack frame for emptyVase(1) the function execution is done, so print the current flowerInVase which is 1. Go back to the previous stack frame, every time print the currently stored variable until the last stack frame is reached.
And that is why the order is reverse! That is also why if you change the order of the print and the function execution it will look as expected.
public static void emptyVase( int flowersInVase ) {
// if there is a flower to take from the vase
if( flowersInVase > 0 ) {
// print the count of flowers BEFORE one is taken!
System.out.println(flowersInVase);
// take one flower and put it aside
emptyVase( flowersInVase - 1 ) ;
} else {
// the vase is empty, nothing to do
System.out.println(flowersInVase);
// print 0!
}
}
This will produce:
7
6
5
4
3
2
1
0
The vase is actually empty, but because your condition is flowerInVase > 0, this means when the last call is made with emptyVase(0) the else part is taken and you don't print there the value of the counter. Add a print there and you will see an empty vase.
Your approach (and the example) for understanding recursion is good. I think the important thing to notice in your example is the fact, that the recursive call interrupts the current function call and starts a new one (executes the same function again), but the previous call is remembered and once the new call is done, the flow continues from where it was interrupted!
You could imagine every recursive call as a creation of a box in a box:
|-------------------------------|
|--- emptyVase(7) --- |
| |
| |--- emptyVase(6) ---||
| | ||
| | |--- emptyVase(5) ---||
| | | ||
| | | |... and so on ||
| | | |---emptyVase(0)---||
| | | | S.out.println(0) ||
| | | |------------------||
| | |----------------------||
| | System.out.println(6) ||
| |--------------------------||
| System.out.println(7); ||
|-------------------------------|
The deeper the recursion, the more boxes you have.
This is also where the problem is. Recursion is pretty expensive in terms of memory allocation and because the computers have a finite amount of memory, if the recursion creates too many boxes, the execution of the program reaches the maximum allowed count of boxes = stack frames and says stack overflow. Be aware that my explanation is a very basic one. For a thorough explanation of the so called call stack have a look at this Wikipedia article - Call stack.
Each call to emptyVase() will print a flowersInVase value , so basicly you will call System.out.println() 7 times. The first print '1' is for the last call to emptyVase(), the second one '2' is for the before last one and so again .The last one '7' is for the first call to emptyVase() witch was realy 7 flower in the vase.