Two recursive calls in a Merge Sort function confusion - java

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.

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.

How does loop in recursion work?

I'm learning recursion now, and I thought I quite understood how recursion works, and then I saw this code, and my head is about to explode.
I know this simple recursion works like
public void recursivePrint(int number){
if(number == 0{
return;
}
System.out.println(number + " ");
recursivePrint(number - 1);
}
If the parameter "number"'s value is 2.
public void recursivePrint(2){
if(number == 0{
return;
}
System.out.print(2 + " ");
recursivePrint(2 - 1);
}
public void recursivePrint(1){
if(number == 0{
return;
}
System.out.print(1 + " ");
recursivePrint(1 - 1);
}
and then stops because it meets its base case.
What about this print all permutations of a string function?
private void permute(String str, int l, int r)
{
if (l == r)
System.out.println(str);
else
{
for (int i = l; i <= r; i++)
{
str = swap(str,l,i);
permute(str, l+1, r);
str = swap(str,l,i);
}
}
}
There is a recursive call inside a for loop. If the input value is "ab", how does this recursion function work? Can you explain as I wrote above?
I got this code form geeksforgeeks, and there's a video for this, but I can't understand this since I don't know how loop works in recursion.
Using permute function you are generating strings where lth char is being replaced by one of the char following it. With the for loop inside it, you are touching onto each of those following characters one at a time.
With several call to permute, you are able to advance till the end position of the string, and that end is checked by if (l == r)
Take the case of abc.
abc
/ | \
Level 1 a(bc) b(ac) c(ba) (Here three new call to permute are made out of permute with l=1)
Goes on...
FYI, permutation isn't that simple to understand if you are new to recursion or programming. For easy understanding use pen-paper.
Recursion occurs when a method calls itself. Such a method is called recursive. A recursive method may be more concise than an equivalent non-recursive approach. However, for deep recursion, sometimes an iterative solution can consume less of a thread's finite stack space.
What is recursion:
In general, recursion is when a function invokes itself, either directly or indirectly. For example:
// This method calls itself "infinitely"
public void useless() {
useless(); // method calls itself (directly)
}
Conditions for applying recursion to a problem:
There are two preconditions for using recursive functions to solving a specific problem:
There must be a base condition for the problem, which will be the endpoint for the recursion. When a
recursive function reaches the base condition, it makes no further (deeper) recursive calls.
Each level of recursion should be attempting a smaller problem. The recursive function thus divides the problem into smaller and smaller parts. Assuming that the problem is finite, this will ensure that the recursion terminates.
In Java there is a third precondition: it should not be necessary to recurse too deeply to solve the problem;
The following function calculates factorials using recursion. Notice how the method factorial calls itself within the function. Each time it calls itself, it reduces the parameter n by 1. When n reaches 1 (the base condition) the function will recurse no deeper.
public int factorial(int n) {
if (n <= 1) { // the base condition
return 1;
} else {
return n * factorial(n - 1);
}
}

Recursion! I'm creating a method that counts back up and then down to a certain number, but I keep getting stuck in an infinite loop

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.

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.

Reversing recursive java methods

I am reading a book called "Think Java: How to think like a Computer Scientist", and I recently covered recursive methods.
public static void countdown(int n)
{
if (n == 0) {
System.out.println("Blastoff!");
} else {
System.out.println(n);
countdown(n - 1);
}
}
This would be a normal recursive method used to count down to 0 and I understand what is happening, but if you make the recursive call before the System.out.println like this
public static void countdown(int n)
{
if (n == 0) {
System.out.println("Blastoff!");
} else {
countdown(n - 1);
System.out.println(n);
}
}
it counts the opposite way, so If I gave the argument 3 for both of these conditional statements the 1st one goes "3, 2, 1, Blastoff!" but the 2nd 1 goes "Blastoff, 1 ,2 ,3".... I don't understand how this works, can someone try to explain what is happening in this code that makes it count in the opposite way?
I'll try to visualize it for you.
First method
countdown(3) (first call)
"3" (sysout)
countdown(3-1) (second call)
"2" (sysout)
countdown(2-1) (third call)
"1" (sysout)
countdown(1-1) (fourth call)
"Blastoff!" (n == 0)
Second method
countdown(3) (first call)
countdown(3-1) (second call)
countdown(2-1) (third call)
countdown(1-1) (fourth call)
"Blastoff!" (n == 0. going back up call stack)
"1" (sysout)
"2" (sysout)
"3" (sysout)
Think of it this way... In the first case you will always print before going down the next function, so...
countdown(3)
System.out.println(3)
countdown(2)
System.out.println(2)
countdown(1)
System.out.println(1)
countdown(0)
System.out.println("Blastoff")
Result: 3 2 1 Blastoff
In the second case, because you print it first, your run will go all the way down the recursion until the base case to start printing...
countdown(3)
countdown(2)
countdown(1)
countdown(0)
System.out.println("Blastoff")
System.out.println(1)
System.out.println(2)
System.out.println(1)
Result: 1 2 3 Blastoff
Recursion is tough! I hope I helped :)
It doesn't count "the opposite way", it's just that it "unravels" in an order you are perhaps not expecting. Try writing out what you expect to happen and I'll be happy to help resolve the misconception.
The issue is that the print line is going to wait until your function call(s) have finished. Therefore it will call the function 3 times in a row before it gets to the first print line
The whole point of recursion is that every step gets its own "stack frame" with its own local variables, that it remembers.
So even if you change n inside of one iteration, the function that called this iteration will still retain its own value of n. When the time comes to print this n it will still be the original value (one bigger than the one in the following iteration).

Categories

Resources