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.
Related
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.
So, I am currently creating a method for an assignment using recursion. I need to take an int, then print going down until it hits 0. After that, I need to print going up until it hits the original number, then stopping. Here's my code so far.
public static void recursivePrinter(int levels)
{
final int start = levels;
if (levels < start ) {
System.out.println("Going up! " + levels);
recursivePrinter(levels + 1);
}
else {
System.out.println("Going down! " + levels);
recursivePrinter(levels - 1);
}
return;
}
You don't reach the return; statement. the code always go in the else statement. to keep track of the starting number you could use a global variable . also you need to add a condition where the recursion should finish. so you can try some thing like this :
static int start = 10;
public static void recursivePrinter(int levels)
{
if (levels < start ) {
System.out.println("Going up! " + levels);
recursivePrinter(levels + 1);
}
else {
System.out.println("Going down! " + levels);
// recursivePrinter(levels - 1);
start-- ;
}
return;
}
In an attempt to provide a meaningful answer to help future visitors (as opposed to the comment thread on the question above)...
The initial problem was two-fold:
The method had no condition in which it doesn't recursively call itself. Which results in an infinite recursion. There must always be some condition by which the method stops recursion.
The method was locally storing a value that it doesn't need, and the logic was incorrectly assuming that value won't be different for each call to the method.
Essentially, a recursive method almost always follows a basic structure:
method(argument) {
terminating condition;
state change or method action;
recursive call;
}
Depending on the state change or the method action, this can be a bit more complex. But the basic components are generally always there in one form or another.
In your case, the argument is an integer, the terminating condition is testing whether that integer is a known value, the state change is changing the integer, the method action is printing the integer, and the recursive call is invoking the method with the new integer.
Based on your comment above:
It's supposed to count down from 3 (3, 2, 1) and then back up to 3 (1, 2, 3).
Consider the following pseudo-code (so as to not do your homework for you) structure:
myMethod(level) {
// terminating condition
if level is 0
return
// method action
print level
// recurse
myMethod(level - 1)
}
This would be a great time to step through the code in your debugger and see what a recursive method call actually does. Each time the method is invoked, it's an isolated action unaware of any other invocations of the method. It's "building a stack" of calls to itself. When the terminating condition is reached, that stack will "unwind" and those calls will all return to each other in reverse order.
Given this, printing the numbers "counting back up" is a natural result of just printing it again in the method:
myMethod(level) {
// terminating condition
if level is 0
return
// method action
print level
// recurse
myMethod(level - 1)
// more method action
print level
}
That last operation simply prints the value a second time. But it does so after the recursive call, therefore after all printing of lower numbers done within that recursive call, regardless of how many there are.
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.
In the following function why After showing Hello(6,5,....1),then space shows increment in counter?
private void myMethod(int counter)
{
if (counter == 0)
{
System.out.println("");
}
else
{
System.out.println("Hello" + counter);
myMethod(--counter);
System.out.println("" + counter);
}
}
Program Output when 6 is passed to method:
Hello6
Hello5
Hello4
Hello3
Hello2
Hello1
0
1
2
3
4
5
The second print is first called if the recursion is fully done, this means it counts backwards, since the last called method finishes first.
If that's what you mean.
(not actually code but used for a diagram)
When using myMethod(3):
mM(3)->|prints: "Hello3"
|mM(2)-------------->|prints: "Hello2"
|prints:.... |mM(1)-------------->|prints: "Hello1"
|prints.... |mM(0)----------->|prints: ""
|prints....
because each else has three statements, and they do them in order from top to bottom, the first print statement is executed first, and then the recursion happens next, which temporarily skips the the second print until the base statement 0 is reached, and then it goes backwards and does the second print for each else. (if this is what you're asking)
I have been out of touch with Algorithms for a while and have start revising my concepts these days. To my surprise the last i remember of my recursions skill was that i was good at it but not anymore. So, i have a basic question for you guys which is confusing me. Please see the below code first ..
private void mergesort(int low, int high) {
if (low < high) {
int middle = (low + high)/2 ;
System.out .println ("Before the 1st Call");
mergesort(low, middle);
System.out .println ("After the 1st Call");
mergesort(middle+1, high);
System.out .println ("After the 2nd Call");
merge(low, middle, high);
}
}
The function call
mergesort(0,7);
And the output is
Before the 1st Call
Before the 1st Call
Before the 1st Call
After the 1st Call
After the 2nd Call
After the 1st Call
Before the 1st Call
After the 1st Call
After the 2nd Call
After the 2nd Call
After the 1st Call
Before the 1st Call
Before the 1st Call
After the 1st Call
After the 2nd Call
After the 1st Call
Before the 1st Call
After the 1st Call
After the 2nd Call
After the 2nd Call
After the 2nd Call
The thing confusing me in the above code and result is the second recursive call. I am understanding the flow until the fourth output line ( i.e : After the 1st Call). But i cannot understand why does it outputs ( After the 2nd Call ) after the ( After the 1st Call ). According to whati am understanding from the code After the output ( After the 1st Call ) the mergesort function with parameter (middle+1, high) should be called and it should output ( Before the 1st call ) and go into the recursive call with mergesort (low, middle). I am comfartable with one recursive call functions and understand and am sync with foreg fibonacci example .
On the fourth output line, you have returned from the first call and the subsequent 2 recursive calls, so now control reaches the System.out .println ("After the 1st Call");
So, the condition low < high is false after the second recursive call, so you just exit the function. Then, control returns to the line right after the second recursive call.
TIP
One thing I used to do when learning recursion is to keep track of stack depth (e.g. pass in a parameter for this) and then on your output you indent your output based on stack depth. This helps you visualize where you are in the recursive chain, and makes debugging easier.
So your debugging input could look similar to the following:
entered method, low = 0, high = 10
entered method, low = 0, high = 5
entered method, low = 0, high = 2
exiting method, low = 0, high = 2
exiting method, low = 0, high = 5
exiting method, low = 0, high = 10
Just follow the execution...
First call 0,7 --> enters if, middle = 3 (integer division), calls again as (0,3)
Second call 0,3 --> enters if, middle = 1, calls again as (0,1)
Third call 0,1 --> enters if, middle = 0, calls again as (0,0)
Fourth call 0,0 --> does not enter if, back to third call
Third call 0,1 --> calls as middle+1,high which is (1,1)
Fifth call 1,1 --> does not enter if, back to third call
Third call 0,1 --> calls the string you didn't expect
can continue on but that is where the string you aren't expecting is executed.
You could print out the values of high and low too. It would be much easier to follow the recursion.
Try printing the value of the middle variable.
Best practise dictates that you don't code in "Before function" style debugging messages without any variable output.
After 4 line of output low = 0, middle = 0, high = 1 so calling mergesort(middle+1,high) wont print nothing ( 1 < 1 is false)
The indentation in the following corresponds to the recursion:
mergesort(0, 7)
middle=3
"Before the 1st Call"
mergesort(0, 3)
middle=1
"Before the 1st Call"
mergesort(0, 1)
middle=0
"Before the 1st Call"
mergesort(0, 0)
(0 < 0) is false so return
"After the 1st Call"
mergesort(1, 1)
(1 < 1) is false so return
"After the 2nd Call"
etc ...
Run this piece of code to understand recursion well.I have considered the stack depth in the console.Hope it makes it easy to understand!
#include "stdafx.h"
#include <iomanip>
using namespace std;
static int stackdepth=0;
void mergesort(int[],int,int);
void merge(int[],int,int,int);
void space(int);
int main(int argc,char *argv[])
{
int a[8]={5,7,1,4,9,3,2,0};
mergesort(a,0,7);
for(int i=0;i<10;i++)
// cout<<a[i]<<endl;
return 0;
}
void mergesort(int a[],int low,int high)
{
int mid;
if(low<high)
{
mid=(low+high)/2;
space(stackdepth);
cout<<"First Recursion Enter";
cout<<" Low :"<<low<<" Mid :"<<mid<<endl;
stackdepth++;
mergesort(a,low,mid);
stackdepth--;
space(stackdepth);
cout<<"First Recursion Exit";
cout<<" Low :"<<low<<" Mid :"<<mid<<endl;
space(stackdepth);
stackdepth++;
cout<<"Second Recursion Enter";
cout<<" Mid+1 :"<<mid+1<<" High :"<<high<<endl;
mergesort(a,mid+1,high);
stackdepth--;
space(stackdepth);
cout<<"Second Recursion Exit";
cout<<" Low :"<<mid+1<<" High :"<<high<<endl;
space(stackdepth);
cout<<"Merge Low :"<<low<<" Mid :"<<mid<<"High :"<<high<<endl;
merge(a,low,mid,high);
cout<<endl;
space(stackdepth);
cout<<"------------------------------------------------------------------------------------------"<<endl;
}
}
void space(int stackdepth)
{
for(int i=0;i<stackdepth;i++)
cout<<" ";
}
void merge(int a[],int low,int mid,int high)
{
// cout<<endl;
// cout<<"Merging Begins"<<endl;
int b[8];
int i,k,j;
i=low;k=low;j=mid+1;
while(i<=mid && j<=high)
{
if(a[i]<a[j])
{
b[k++]=a[i++];
}
else
{
b[k++]=a[j++];
}
}
while(i<=mid)
b[k++]=a[i++];
while(j<=high)
b[k++]=a[j++];
space(stackdepth);
for(int i=low;i<=high;i++)
{
a[i]=b[i];
cout<<a[i]<<" ";
}
//cout<<"Low :"<<low<<" Mid :"<<mid<<" High :"<<high<<endl;
// cout<<"Merging Ends"<<endl;
// cout<<endl;
}
Merge Sort uses a recursive algorithm to create a complete binary tree with a height of Log N, being N the number of nodes of that tree (this is why is so efficient). In the next image you can see step by step what is the flow of execution of this algorithm for your case, with the binary tree that is created (which I think is the best way to understand how it works):
Binary tree that is generated using Merge Sort with an array of 8 positions
What Merge Sort does is to split the array in halves recursively, going first to the lowest halves until we reach one unitary element, and then go and split the higher ones from the lowest element recently reached. This is why it calls itself two times per each previous call, in order to create a complete binary tree that stops when we reach one unit (with leaf nodes) and only merge when we have two (with parent nodes). In the following image you can see how your array is split recursively, step by step:
Step by step division of an array of 8 elements using Merge Sort
Go to eclipse debug tool. Follow the step and you will find the rule double recursion. Thats what I do.