Understanding Java recursion using Eclipse's debugger - java

I am going through some simple recursion exercises in Java in order to understand the concept (which I struggle with). For all my study up to this point, I have relied heavily on Eclipse's debugger in order to understand exactly what my code is doing. However, when it comes to recursion, I find this not to be the case, because it is difficult to track exactly what is happening.
Considering the following code, a method that returns the nth Fibonacci number:
public int fibonacci(int n) {
if (n == 0 || n == 1) {
return n;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
When using the debugger for this code, it's pretty difficult to track exactly what is happening and where/when. With only one variable, it changes every step, and, with a small n value, such as 7, it is already becoming difficult to track, due to the fact that there are so many steps that are executed before 13 is eventually reached.
I would like to know:
How can I debug my recursion code (in general) in a better way, in order to better understand recursion?
Am I focussing too much on debugging for this sort of thing, considering the concept return fibonacci(n - 1) + fibonacci(n - 2) is simple to understand?

How can I debug my recursion code?
First, make sure you have switched to the Debug perspective and you're seeing the correct windows (Variables, Expressions, Debug and your source code) e.g. like this:
Next, note that in Debug you can see how often the method is currently called. This list will grow and shrink depending on how many methods were called and have not returned yet.
You can click on one of the methods to change the scope. See how the contents of Variables changes when you change the scope.
Finally, to check arbitrary things, enter expressions in the Expressions window. This is almost like live coding. You can inspect virtually anything.
Am I focussing too much on debugging?
No. Learn doing it right and it will save you much time later.
Adding a System.out.println() needs to recompile and you need to reproduce the situation which is not always that simple.

You can debug it using a simple System.out.prinln() in each instruction where you print n value and its fibonnacci value.
Here's an example code:
public int fibonacci(int n) {
if (n == 0 || n == 1) {
System.out.println("your value is: " +n+ " and its Fibonacci value is: "+n);
return n;
} else {
System.out.println("your value is: " +n+ " and its Fibonacci value is: "+fibonacci(n - 1) + fibonacci(n - 2));
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
You can test the DEMO here.

"Inline" code makes it more difficult to use the Eclipse debugger because it has a strong focus on showing local variables which are not present. You can make this easier to step through by making things more verbose and saving to variables. This way you can more easily see what is happening and what results are. For example, modifying your code as follows will make it easier to use the debugger on:
public int fibonacci(int n) {
if (n == 0 || n == 1) {
return n;
} else {
int nMinus1 = fibonacci(n - 1);
int nMinus2 = fibonacci(n - 2);
int retValue = nMinus1 + nMinus2;
return retValue;
}
}
DISCLAIMER: I have not attempted to compile this code.

It took me a while to grasp recursion and, for one reason or another, I never found the debuggers useful. I'll try to explain you how I do and it doesn't involve the debugger (disclaimer: this is a personal method and it might by incorrect or not general).
In recursive code you always have at least a termination block and a
recursion block. Isolate mentally these 2 sections.
return n; -> termination block
return fibonacci(n - 1) + fibonacci(n - 2); -> recursion block
The recursion block express the abstract rule(s) of recursion. Instead of having those values in variables Fn1 and Fn2, you obtain these values using the same function. Think about a brick wall: your recursive function creates the wall adding a brick to an existing wall. Inside the recursion block, at a certain step, you don't mind who and how the existing wall has been created, you simply add to it a new brick. It happens then that the wall has been created by the same function, one brick at the time.
At the termination block the code is called with some values. What should happen at the end of the process to that value? Speaking about Fibonacci, at the end of the process (n = 1 or n = 0) I have to again add these number to the total. This is done by the recursive block. In other words the termination block gives the concrete values (and not a process on how to obtain them) to the recursion block.
When I have to troubleshoot I print the values at every step, and this is the best solution I've found for me. Then I check that they are what they are supposed to be. For your Fibonacci, I would like to see an output like
Code:
public static int fibonacci( int n ) {
System.out.println( "\nInput value: " + n );
if( n == 0 || n == 1 ) {
System.out.println( "Terminating block value: " + n );
return n;
}
else {
System.out.println( "Recursion block value: fibonacci(" + (n - 1) + ") + fibonacci(" + (n - 2) + ")" );
int result = fibonacci( n - 1 ) + fibonacci( n - 2 );
System.out.println( "Recursion block return value: " + result );
return result;
}
}
Output:
Input value: 4
Recursion block value: fibonacci(3) + fibonacci(2)
Input value: 3
Recursion block value: fibonacci(2) + fibonacci(1)
Input value: 2
Recursion block value: fibonacci(1) + fibonacci(0)
Input value: 1
Terminating block value: 1
Input value: 0
Terminating block value: 0
Recursion block return value: 1
Input value: 1
Terminating block value: 1
Recursion block return value: 2
Input value: 2
Recursion block value: fibonacci(1) + fibonacci(0)
Input value: 1
Terminating block value: 1
Input value: 0
Terminating block value: 0
Recursion block return value: 1
Recursion block return value: 3
You can also find useful to read about Induction, which is strictly related to recursion.

Related

I Need an explanation about the next recursion (I'm a beginner)

I know that lowkey it does 1 + 2 + 3 + 4 = 10, but I want to know how exactly it does that
public class Main {
public static int sum(int n) {
if(n == 0) return 0;
return sum(n - 1) + n;
}
public static void main(String[] args) {
System.out.println(sum(4));
}//main
}//class
public static int sum(int n) {
if(n == 0) return 0;
return sum(n - 1) + n;
}
When you call sum(4), the compiler does the following steps:
sum(4) = sum(3) + 4, sum(3) then calls sum(int n) and go to next step
sum(3) = sum(2) + 3, sum(2) then calls sum(int n) and go to next step
sum(2) = sum(1) + 2, sum(1) then calls sum(int n) and go to next step
sum(1) = sum(0) + 1, sum(0) then calls sum(int n) and go to next step
sum(0) = 0, return the value and bring it to previous step.
Then with backtracking, the compiler brings the value of sum(0) to the formula sum(0) + 1, so the value of sum(1) is 1. And so on, finally we get sum(4) is 10.
The key to understanding how this recursion work is the ability to see what is happening at each recursive step. Consider a call sum(4):
return
sum(3) + 4
sum(2) + 3
sum(1) + 2
sum(0) + 1
return 0 in next recursive call
It should be clear how a sum of 10 is obtained for sum(4), and may generalize to any other input.
Okay so lets understand it :
you call the method from main method passing the argument as 4.
It goes to method , the very first thing it checks is called as base condition in recursion . Here base condition is if n == 0 return 0.
We skipped the base condition since n is not yet zero . we go to return sum(n-1)+n that is sum(4-1)+4 . So addition will not happen , because you made the recursive call again to sum method by decrementing the n value to n-1 , in this case it is 3.
You again entered the method with n =3, check the base condition which is not valid since 3 != 0 , so we go to return sum (n-1)+3 , which is sum(3-1)+3
Next recursive call where n = 2 , base condition is not valid 2!=0 , so we return sum(n-1)+2that is sum(2-1)+2.
Next call with n = 1 , base condition is not valid , we go to return sum(n-1)+1 that is sum(1-1)+1.
Next recursive call with n = 0 , so now base condition is met , means it is time to stop the recursion and keep going back to from where we came to get the desired result. So this time we returned 0.
Lets go back to step 6 , with 0 we got and compute the addition part of sum(1-1)+1 . You got sum(1-1) => sum(0) = . So sum(1-1)+1 will be equal to 0+1=1
One more step back with 1 as value to step 5 , where we have sum(2-1)+2 = sum(1)+2 , sum(1) you know , which is 1 , so we will return 1+2=3 from this recursive call.
One step back with value as 3 , to step 4 , sum(3-1)+3 = sum (2)+3 = 3+3 =6 .
Going one step back with 6 as value to step 3 , sum(4-1)+4 = sum(3)+4 = 6+4 = 10 . And that is where we started from . You got the result as 10.
Recursion itself is very easy to understand.
From a mathematical point of view, it is just a simple function call, such as your code:
public static int sum(int n) {
if(n == 0) return 0;
return sum(n - 1) + n;
}
/*
sum(0) = 0
sum(1) = 1
sum(n) = n + sum(n-1)
*/
In fact, the concept of recursion has been introduced in high school. It is the "mathematical construction method" that is often used to prove sequence problems. The characteristics are obvious: the structure is simple and the proof is crude. As long as you build the framework, you can prove it in conclusion. So what is a recursive "simple structure" framework?
Initial conditions: sum(0) = 0
Recursive expression: sum(n) = sum(n-1) + n
And in fact about the sum() function, every calculation starts from sum(0), and it is natural. Even if you are asked to calculate sum(1000), all you need is paper, pen, and time, so recursion itself is not difficult.
So why recursion give people an incomprehensible impression? That's because "recursive realization" is difficult to understand, especially using computer language to realize recursion. Because the realization is the reverse, not to let you push from the initial conditions, but to push back to the initial conditions, and the initial conditions become the exit conditions.
In order to be able to reverse the calculation, the computer must use the stack to store the data generated during the entire recursion process, so writing recursion will encounter stack overflow problems. In order to achieve recursion, the human brain has to simulate the entire recursive process. Unfortunately, the human brain has limited storage, and two-parameter three-layer recursion can basically make you overflow.
Therefore, the most direct way is to use paper to record the stacks in your head. It is very mechanically painful and takes patience, but problems can often be found in the process.
Or, go back to the definition of recursion itself.
First write the architecture and then fill it in. Define the exit conditions and define the expression.
Second implement the code strictly according to the architecture. Recursive code is generally simple enough, so it is not easy to make mistakes in implementation. Once there is a problem with the program result, the first should not be to check the code, but to check your own definition.
Meeting Infinite loop? The initial conditions are wrong or missing; wrong result? There is a problem with recursion. Find out the problem, and then change the code according to the new architecture. Don't implement it without clearly defining the problem.
Of course, it really doesn't work. There is only one last resort: paper and pen.

Recursion confusion with multiple return

I'm still wrapping my mind around recursion, and I think I get basic ones like factorial. But I'd like further clarification when the return statement is a little more complex like on the following snippet:
/**
* #param n >= 0
* #return the nth Fibonacci number
*/
public static int fibonacci(int n) {
if (n == 0 || n == 1) {
return 1; // base cases
} else {
return fibonacci(n-1) + fibonacci(n-2); // recursive step
}
}
In the return statement, does the fibonacci(n-1) completely recur through, before going down the fibonacci(n-2) step (does that make sense)? If so, this seems very difficult to envision.
Yes, one invocation will recurse all the way down and return, before the other one starts executing.
The order of invocation in Java is well-defined: fibonacci(n-1) goes before fibonacci(n-2).
Edit: Since the question originally included [C++] tag, here is the C++ part of the story: one of the two invocations still has to complete before the other one starts to run, but which one, fibonacci(n-1) or fibonacci(n-2), is unspecified.
Since the function has no side effects, it does not matter which of the two invocations gets to run first. The only thing that is important for understanding of recursion is that both invocations must complete, and their results must be added together, before the invocation at the current level returns.
It isn't much more different than calling a different function than itself. It needs to finish before the calling function can do anything with the result.
finobacci(0); // ==> 1 (since n is zero, the base case is to return 1)
fibonacci(1); // ==> 1 (since n is one, the base case is to return 1)
Now lets try 2 which is not the base case:
fibonacci(2); // == (since it's not the base case)
fibonacci(1) + fibonacci(0); // == (both calls to fibonacci we already haver done above)
1 + 1 // ==> 2
So in reality what happens is that the call to fibonacci2 waits while each of the two recursive calls to finish, just like a function that does System.out.println would wait until it had printed the argument before continuing to the next line. Recursion isn't that special.
Trivia: This is the original series from Fibonacci himself. Modern mathematicians start the series with n as the base case result making the series 0, 1, 1, 2, ... rather than 1, 1, 2, 3, ....
it works in this way:
Fibonacci program:
public int fibonacci(int n) {
if(n == 0)
return 0;
else if(n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
Explanation:
In fibonacci sequence each item is the sum of the previous two. So, as per recursive algorithm.
So,
fibonacci(5) = fibonacci(4) + fibonacci(3)
fibonacci(3) = fibonacci(2) + fibonacci(1)
fibonacci(4) = fibonacci(3) + fibonacci(2)
fibonacci(2) = fibonacci(1) + fibonacci(0)
Now you already know fibonacci(1)==1 and fibonacci(0) == 0. So, you can subsequently calculate the other values.
Now,
fibonacci(2) = 1+0 = 1
fibonacci(3) = 1+1 = 2
fibonacci(4) = 2+1 = 3
fibonacci(5) = 3+2 = 5
In multiple recursion the program calls itself with its first call until the base case is reached, in this case fibonacci(n-1); after that the recursion stops and return his value to continue calling the value to the second part of the recursion fibonacci(n-2).
If you don't visualize the multiple recursion in the program, this
fibonacci recursion tree may be helpful.

Java recursion outputs name forwards and backwards

I wrote a basic recursion problem in class a long time ago and I'm trying to remember how I'm getting the output that prints.
Its basically prints out a name forwards and backwards. I understand how it prints the name forwards but I'm clueless as to how it prints the name backwards. I did a debug to see step by step what is going on but can't understand how index is decreasing after the name prints forwards.
public class CharRecursion
{
public static void printName(String name, int index)
{
if(index > name.length() - 1)
{
return;
}
else
{
System.out.println(name.charAt(index));
printName(name, index + 1);
System.out.println(name.charAt(index));
}
}
public static void main(String[] args)
{
printName("Brian", 0);
}
}
The output is BriannairB
The backwards part comes from the second System.out.println(name.charAt(index)); statement.
This one is called only once the recursive call has ended, recursively, so you end up with the reverse String, look at the suffix markers :
System.out.println(name.charAt(index) + " - ");
printName(name, index + 1);
System.out.println(name.charAt(index) + " * ");
You get :
B -
r -
i -
a -
n -
n *
a *
i *
r *
B *
Since the actual sequence of calls is :
printName(name, 0) > printName(name, 1) > printName(name, 2) > printName(name, 3) > printName(name, 4)
The first call to resolve your second println statement will be printName(name, 4), then printName(name, 3), etc.. and the order of the printing becomes :
System.out.println(name.charAt(4) + " * ");
System.out.println(name.charAt(3) + " * ");
System.out.println(name.charAt(2) + " * ");
System.out.println(name.charAt(1) + " * ");
System.out.println(name.charAt(0) + " * ");
The way to understand this is to step through it manually, using pen and paper. I can't recommend strongly enough that you actually to this, physically, with real pieces of paper, until you understand what's going on.
Use one sheet of paper to record output.
Use a new separate sheet of paper for each invocation of printName().
Start at main(). When you see printName("Brian", 0), that's a signal to start a new sheet of paper. At the top of the sheet, write the inputs: name -
"Brian", index = 0.
Now you're in printName(), so go through it step by step. 0 is less than "Brian".length() - 1, so you can skip to the else block:
System.out.println(name.charAt(index)); - so write the result of "Brian".charAt(0) on your output sheet: B.
printName(name, index + 1) -- since you're seeingprintName()again, take another sheet of paper, write the inputsname="Brian", index = 1` at the top, and place this on top of the previous sheet.
Keep working in this way, and you will keep adding to your stack of paper. This is directly analogous to the execution stack that Java maintains; this is the same stack that you see in a stacktrace.
Eventually you'll reach a point where index = "Brian".length() -1, so you return. When you see return, remove the sheet you're working on, screw it up and throw it in the bin. The runtime has finished with this invocation of the method. Continue with the sheet underneath, where you left off. You are now at the second System.out.println(name.charAt(index));. So write that character on your output sheet.
When you finish, you will find you have written "BriannairB" on your output sheet, and you should have a better understanding of recursion.
Each piece of paper represents a stack frame. Bear in mind:
At a given moment during execution, only the topmost stack frame is "visible" as far as the execution is concerned.
Local variables and parameters are stored in the stack frame. At some moment in your execution, the value of index in the current stack frame will be 3. This has no effect on the value of index in the stack frame below -- that is a completely separate piece of storage, and will still be 2 when the 3 frame ends and is popped off the stack.
Once you get the hang of this, though, you can look at it at a more "declarative" level. What does printName("Brian",0) do?
It prints "B" then printName("Brian", 1) then "B".
I think this implementation is slightly easier to understand:
void printName(String s) {
if(s.length() > 0) {
System.out.println(s.charAt(0));
printName(s.substring(1));
System.out.println(s.charAt(0));
}
}
So, printName("Brian") writes B then printName("rian") then B.
Or going from the deepest the stack will go:
printName("") writes nothing.
Therefore printName("n") writes n then printName("") then n -- which is nn.
Following is the execution sequence of your program. Program calls printName("Brian",index) function recursively which executes first System.out.println(name.charAt(index)); before each call. When index reaches 5 function calls start returning and second System.out.println(name.charAt(index)); is executed after each return.

Learning Java - Do not fully understand how this sequence is calculated (Fibonacci) [duplicate]

This question already has answers here:
Java recursive Fibonacci sequence
(37 answers)
Closed 8 years ago.
I am learning Java and I have this code from the internet and running it in Eclipse:
public class Fibonacci {
public static void main (String [] args) {
for (int counter = 0; counter <= 3; counter++){
System.out.printf("Fibonacci of %d is: %d\n", counter, fibonacci(counter));
}
public static long fibonacci(long number) {
if ((number == 0) || (number == 1))
return number;
else
return fibonacci(number - 1) + fibonacci(number - 2);
}
}
I've tried to understand it but cannot get it. So I run through the code and counter gets passed in through the fibonacci method. As counter starts at 0 and this is what gets passed first, then 1 and I understand the method passes back 0 and then 1.
When it reaches 2: it will return 2-1 + 2-2 = 2 and it does return this.
When it reaches 3: it will return 3-1 + 3-2 = 3 but it does not return 3 it returns 2.
Please can someone explain to me why as I cannot figure this out?
Thanks
First, I have to tell you that this recursive version has a dramatic exponential cost. Once you understand how it works, my advice for you would be to learn about tail recursivity, write a tail-recursive solution, an iterative solution, and compare them to your current method for high values of "number".
Then, your function basically uses the mathematical definition of the Fibonacci sequence :
f0 = 1, f1 = 1, fn = fn-1 + fn-2 for all n >= 2
For example if we call fibonacci(3), this will return fibonacci(2) + fibonacci(1). fibonacci(2) will be executed first and will return fibonacci(1) + fibonnacci(0). Then fibonacci(1) will return immediately 1 since it is a terminal case. It happens the same thing with fibonnacci(0), so now we have computed fibonnacci(2) = 1 + 0 = 1. Let's go back to fibonacci(3) which has been partially evaluated at this point : 1 + fibonnacci(1). We just have to compute fibonnacci(1) and we can finally return 1 + 1 = 2.
Even in this little example, you can see that we evaluated twice fibonacci(1), that is why this version is so slow, it computes many times the same values of the sequence, and it gets worth when "number" is high.

Why do i get a StackOverflowError

I made a function that computes the sum of digits of an integer. Trying to make the code shorter, I put in comment the if statement to see if it would still work so I can remove it but I get a StackOverflowError, why?
This is my code:
public static int sumDigits(int n) {
//if(n%10==n){ return n;}
return n%10+sumDigits(n/10);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(sumDigits(12611));
}
It never returns, but just recurses deeper and deeper.
You do have a return statement, but before returning it needs to compute the value of the expression n%10+sumDigits(n/10) which involves infinite recursion.
NB: Each time you call the function from itself, the function's context (local variables) are added on top of the stack. The stack has a limited size. Eventually you reach that size and StackOverflowError is the error that's thrown in that condition.
That's because there is no stop clause. You will invoke sumDigits forever.
A recursive function can be defined as expressing an operation as a function of that operation on a value closer to an end point.
Hence, every recursive function needs an end condition at some point, otherwise it will recur infinitely (or, more correctly, until you blow your stack).
The basic definition of the "sum of digits" recursive method (for non-negative values of n) is:
def sumOfDigits (n):
if n < 10:
return n
return (n % 10) + sumOfDigits (n / 10) # assumes integer division.
That first bit, the end condition, is very important, and you seem to have commented yours out for some reason.
If you remove that line, your recursion does not have a base case any longer, which means it never returns.
stackover flow error occurs whenever the address stack in the memory allocated for the program can not store any new address.
so when you recursively call sumDigits() the system keep on saving the last tracked in LIFO manner. so that it becomes easy for the system to get back to the previously address, which is must for the recursion.
If you do recursion infinitely or above the memory constraints, you will suffer stackOverflow error.
The statement that you commented out was the base case for this recursive function. Without a base case this function will loop infinitely.
When you work out the example in the main method you get:
sumDigits(12611)
= 1 + sumDigits(1261)
= 1 + ( 1 + sumDigits(126))
= 1 + ( 1 + (6 + sumDigits(12)))
= 1 + ( 1 + (6 + ( 2 + sumDigits(1))))
= 1 + ( 1 + (6 + ( 2 + ( 1 + sumDigits(0))))) //at this point the commented out if statement would have returned
= 1 + ( 1 + (6 + ( 2 + ( 1 + ( 0 + sumDigits(0))))))
= 1 + ( 1 + (6 + ( 2 + ( 1 + ( 0 + ( 0 + sumDigits(0)))))))
...
At this point the program is stuck in an infinite loop. The commented out statement would have returned when n was 1, thus preventing this situation.
Because you are calling sumDigits() from itself and the code that should cause you to return from infinite recursion is commented out. Uncomment line if(n%10==n){ return n;}
Your recursion does not have a terminating condition. Else, you call the recursive function over and over again, eventually the stack will overflow
Uncomment your stop condition.

Categories

Resources