Understanding recursion in Java a little better - java

Ok I'm really confused about something about recursion in Java. Say I have the following code:
static int findShortestString(String[] paths, int lo, int hi) {
if(lo==hi)
return lo;
int minindex=findShortestString(paths,lo+1, hi);
if(safeStringLength(paths[lo])<safeStringLength(paths[minindex]))
return lo;
return minindex;
Now the question is not really about the code itself, but just about how recursion works. minindex is being set equal to a recursive call. So the first time the function run and tries to set minindex to something, it does so, and then the function calls itself. But when does the if statement run then? Will it only run when minindex finally actually holds a real value? I just cant wrap my head around this. If minindex causes the function to recurse and recurse, then when will the if statement ever be checked? When lo==hi? I dont get it:(

minindex is not assigned until findShortestString returns, which won't happen until lo == hi.
Each time the method calls itself, it narrows the difference between lo and hi by 1, so eventually they'll be equal* and that value will be returned.
An example, with paths = ["p1", "path2", "longpath3"]:
lo = 0, hi = 2
lo != hi -> call findShortestString(paths, 1, 2)
lo = 1, hi = 2
lo != hi -> call findShortestString(paths, 2, 2)
lo = 2, hi = 2
lo == hi -> return lo (=2)
lo = 1, hi = 2, minindex = 2
length of "path2" < length of "longpath3" -> return lo (= 1)
lo = 0, hi = 2, minindex = 1
length of "p1" < length of "path2" -> return lo (= 0)
I've tried to illustrate the variable values at each level of recursion using increasing amounts of indentation. At the beginning of each recursive call, the previous values of lo, hi and minindex are saved off (in a structure called a "stack") and the new values used instead. When each invocation of the method returns, the previously saved values are "popped" off the stack for use, and minindex assigned from the previous return value.
*unless lo > hi to begin with, I guess...

Here's a play by play of the execution:
You call findShortestString() yourself
if lo doesn't not equal hi things continue. Otherwise they stop here and the function returns.
Once you call findShortestString() again, everything in this instance of the function completely stops and will not resume until the computer has a value to give minindex (aka the function returns.) We start over in a new instance of the function at the top. The only code executed until one of the functions return is the code BEFORE the method call. This could be compared to a while loop.
We only get beyond that line once one of the function instances has lo==hi and returns.
Control switches to the function instance before that, which assigns the returned lo value to minindex.
If (safeStringLength(paths[lo])<safeStringLength(paths[minindex])) then we return lo. Else, we return minindex. Either way, this function instance is complete and control returns to the one before it.
Each function called is now only executing the code AFTER the method call, as the method will not get called again. We are unwinding the stack of calls. All of the returns will now be from the last 2 statements, as the code at the top does not get executed again. Note how only one function instance returns with the top part of the code, terminating the while loop. All the rest terminate with the return statements in the part of the function after the recursive call.
Eventually the last function returns and you go back to the code you called the function from originally.
Here's a more readable version of what the code is actually doing:
In the code before the recursive call, all that happens is the creation of a chain of calls until lo==hi. Each time the function is called with lo being 1 greater. Here's a sample stack of calls:
findShortestString(2,5);
findShortestString(3,5);
findShortestString(4,5);
findShortestString(5,5);
When they unwind, each function instance compares the string lengths of the strings at the indexes lo and the index the previous index with the shortest string.
compare strings at indexes 2 and 5
if the string at 2 is smaller, compare the strings at indexes 2 and 4.
Otherwise, compare the strings with indexes at 3 and 5.
If lo>hi at the beginning, the code will continue to run until lo overflows an integer and becomes negative, then until lo finally gets all the way up to hi, or 4,94,967,296 - (original lo - original hi). In other words, in will take a long time. To fix this, add a check at the beginning of the method that throws an exception if lo>hi.
The code could be better rewritten as this:
static int findShortestString(String[] paths, int lo, int hi) {
int indexWithShortestString=lo;
for( int i=lo; i<=hi-1; i++) {
//assumption: lo and hi are both valid indexes of paths
if (paths[i+1].length < paths[i].length)
indexWithShortestString=i+1;
}
}

Think of a stack. Every time the recursive method is called a new "frame" is put on top of the stack. The frame contains its own "slots" for each variable, independent and distinct from those in the frames below.
Eventually, a new frame will be created where the value of lo and hi are equal, and the method will return without pushing another frame. (This is called the "base case".) When that return occurs, that frame is popped off the stack, and the frame that was just below it continues its execution at the second if statement. Eventually that frame is also popped off and the same happens to the frame just below, and so on, until execution returns to the original caller.

Each time findShortestString calls itself, minindex will eventually be assigned, then the value is used in the if statement. It is always set the index of the shortest string at a higher index than lo.
So if there is a call stack with 10 levels of findShortestString, minindex is assigned 9 times (the first call is from another function).

This is a really confusing recursive function. But you generally have it correct. Every call to findShortestString() will push the function onto the stack. It will keep doing this until lo==hi. At that point, the stack is unwound and corresponding recursive calls will be assigned to their corresponding ints.
In this function, it seems that you'll only ever be returning lo. Because either (safeStringLength(paths[lo])<safeStringLength(paths[minindex]) will be true and you'll return lo. Or lo==hi will be true and you'll return lo

In order for the statement
int minindex=findShortestString(paths,lo+1, hi);
to evaluate, the method call findShortestString(paths,lo+1, hi) must return a value. Thus the following if statement will not happen until this method call returns a value. However, this method might call itself again, and you get a nesting effect.

Basically an execution of a function ends when a return statement is called. Everything after a return statement which is called no longer matters (or "exists").
Hence, the local variable minindex will only exist in an execution of a findShortestString function when the first if-statement is false.
Treat each execution of a findShortestString function independently, whether they are called recursively or from somewhere else in the code. i.e. different execution of a findShortestString function may return at different paths and have their own values and local variables. Depending on the input values, they may return at line 3, 6 or 7.
minindenx only exists in an execution that can run line 4, and it is assigned findShortestString(paths,lo+1, hi) which is guaranteed have a value, if the code is correct, otherwise you will get an infinite recursion, resulting in a stack overflow (pun unintended).

Related

Java Recursivity misunderstanding

I'm not understanding this code, why it counts up. If I change the order in the print statement with recursivity call It makes sense to me, but as it is why it is counting up. In by book it says that "System.out.println happens just before each recursive call returns. As a result, it counts up instead of down." And I am not understanding It. Appreciate your help.
public static void countdown(int n)
{
if (n == 0)
{
System.out.println("Blastoff!");
}
else
{
countdown(n - 1);
System.out.println(n);
}
}
So, if n != 0, your program running code in "else" block, where is another call to method countdown(n-1). For example, if you put n = 3, this code will be running as long as n > 0. So, basiclly running method run herself, looks like this:
countdown(3) call method countdown(2), and then countdown(2) call countdown(1). It will happen as long as n will be higher than 0. If n == 0, it will print Your message.
you should change the condition 'n == 0' to 'n <=0'. because if you pass negative value then it wont stop and you might see negative number.
lets says if you passed n = -3. then it would keep printing -3, -4...etc.
countdown(n - 1);
System.out.println(n);
It indeed counts up.
Let's take a look at what actually happens: Each countdown call first calls itself, even before anything is written to System.out.
In the following example, let's say I call countdown with 2 as argument.
countdown(2) is called
within this method call, n == 2, so else block is executed
countdown(1) is called
within this method call, n == 1, so else block is executed
countdown(0) is called
within this method call, n == 0 thus the if-condition is true, so "Blastoff!" is printed
this method exits, returning to the method denoted by step 3.
n is printed, which has the value 1.
the method exits, returning to the method denoted by step 1.
n is printed, which has the value 2.
the method exits
Note that each method call has its own local variables, like n. So the output is:
Blastoff!
1
2
as expected. You see that, just according to what the book says, the method calls itself prior to printing something to sysout.

I need help in trying to fully understand the concept of recursion [duplicate]

This question already has answers here:
Understanding recursion [closed]
(20 answers)
Closed 5 years ago.
Before you get started, I have used google countless times in hopes of searching for a very brief and simple explanation of how recursion works when it has a return type. But I guess I'm not as bright as I thought since i still cant understand it quite well.
Take the following code snippet (in java) as an example
public static int recursion(int num)
{
int result;
if (num == 1)
result = 1;
else
result = recursion(num - 1) + num;
return result;
}
I grabbed this code from my professors lecture slide and he said this will return 1 + 2 + 3 + ... + num.
I just need someone to explain how the process works in the method that i provided. Maybe a step by step approach might help me understand how recursion works.
recursion(5) = recursion(4) + 5, let's figure out recursion(4) and come back to this later
recursion(4) = recursion(3) + 4, let's figure out recursion(3) and come back to this later
recursion(3) = recursion(2) + 3, ...
recursion(2) = recursion(1) + 2, ...
recursion(1) = 1, we know this!
recursion(2) = 1 + 2, now we can evaluate this
recursion(3) = (1+2) + 3, and now we can evaluate this
recursion(4) = (1+2+3) + 4, ...
recursion(5) = (1+2+3+4) + 5, the answer to our original question
Note: Without knowing recursion(1), we'd have gone to 0, -1, -2, and so on until forever. This known quantity is called the base case and it is a requirement for recursion.
Basically when there is a stack buildup for each item that is created beyond the last iteration. (Where num=1)
When n>1 the if statement kicks the iteration to the else which 'saves' the result in a stack and calls the same funtion again with n-1
what this effectively does is keep calling the same function until you hit your designated 'base case' which is n=1
Recursion is all about solving a problem by breaking it into a smaller problem. In your case, the question is "how do you sum the numbers from 1 to n", and the answer is "sum up all the numbers from 1 to n-1, and then add n to it". You've phrased the problem in terms of a smaller or simpler version of itself. This often involves separating out a "base case"—an irreducibly simple problem with a straightforward answer.
public static int recursion(int num)
{
int result;
if (num == 1)
result = 1; // Base case: the sum of the numbers from 1 to 1 is 1.
else
result =
// This is the sum of numers from 1 to n-1. The function calls itself.
recursion(num - 1)
// Now add the final number in the list, and return your result.
+ num;
return result;
}
You're defining the unsolved problem in terms of itself, which works because the solution always involves either the base case or a simpler version of the problem (which itself further involves either the base case or an even simpler version of the problem).
I'll close with one of my favorite jokes:
How do you explain recursion to a five-year-old?
You explain recursion to a four-year-old, and wait a year.
Going by the classic code example you posted. if you call your method like so with number passed in as 5:
recursion(5);
In layman terms just to understand, your function will create & call another copy of your function in the else block as below:
recursion(4);
and then
recursion(3);
recursion(2);
recursion(1);
as the number keeps decrementing.
Finally it will call the if part in the final copy of the method as num will satisfy num == 1. So from there it starts unwinding & returning each value to the previous call.
As each method call has its own stack to load method local variables on, there will be n number of stacks created for n calls. When the deepest call in recursion is made, then the stacks start unwinding. Hence recursion achieved
The most important thing however to note is that there is a base-most call in your code, which is done at 1 just because you have the check if (num == 1). Else it would be infinite recursion & of course a fatal & wrong program to write. The base-most call is from where its called as stack unwinding in recursion terms.
Example: Finding the factorial of a number is the most classic examples of recursion.
Performance: Do look into recursion vs iteration and recursion vs looping to see what are the performance impacts of recursion

In a recursive statment, how does java store the past values?

public class Factorial {
int factR(int n){
int result;
if(n==1)return 1;
result=factR(n-1)*n;
System.out.println("Recursion"+result);
return result;
}
I know that this method will have the output of
Recursion2
Recursion6
Recursion24
Recursion120
Recursive120
However, my question is how does java store the past values for the factorial? It also appears as if java decides to multiply the values from the bottom up. What is the process by which this occurs? It it due to how java stores memory in its stack?
http://www.programmerinterview.com/index.php/recursion/explanation-of-recursion/
The values are stored on Java's call stack. It's in reverse because of how this recursive function is defined. You're getting n, then multiplying it by the value from the same function for n-1 and so on, and so on, until it reaches 1 and just returns 1 at that level. So, for 5, it would be 5 * 4 * 3 * 2 * 1. Answer is the same regardless of the direction of multiplication.
You can see how this works by writing a program that will break the stack and give you a StackOverflowError. You cannot store infinite state on the call stack!
public class StackTest {
public static void main(String[] args) {
run(1);
}
private static void run(int index) {
System.out.println("Index: " + index);
run(++index);
}
}
It actually isn't storing 'past values' at all. It stores the state of the program in the stack, with a frame for each method call containing data such as the current line the program is on. But there is only one value for the variable result at any time, for the current method on top of the stack. That gets returned and used to compute result in the frame that called this, and so on backwards, hence the bottom up behaviour you see.
One way to make this less confusing is to take recursion out of the picture temporarily. Suppose Java did not support recursion, and methods were only allowed to call other, different methods. If you wanted to still take a similar approach, one crude way would be to copy paste the factR method into multiple distinct but similar methods, something like:
int fact1(int n){
int result;
if(n==1)return 1;
// Here's the difference: call the 'next' method
result=fact2(n-1)*n;
System.out.println("Recursion"+result);
return result;
}
Similarly define a fact2 which calls fact3 and so on, although eventually you have to stop defining new methods and just hope that the last one doesn't get called. This would be a horrible program but it should be very obvious how it works as there's nothing magical. With some thought you can realise that factR is essentially doing the same thing. Then you can see that Java doesn't 'decide' to multiply the values bottom up: the observed behaviour is the only logical possibility given your code.
well i am trying to understand you,
if someone call likewise then
factR(3) it's recursive process so obviously java uses Stack for maintaining work flow,
NOTE : please see below procedural task step by step and again note
where it get back after current task complete.
result=factR(2)*3 // again call where n=2
-> result=factR(1)*2 // again call where n=1
-> now n=1 so that it will return 1
-> result=1*2 // after return it will become 6
print "Recursion2" // print remaning stuff
return 2;
result=2*3 // after return it will become 6
print "Recursion3" // print remaning stuff
return 3

java.lang.StackOverflowError due to recursion

My problem is that I usually get a java.lang.StackOverflowError when I use recursion.
My question is - why does recursion cause stackoverflow so much more than loops do, and is there any good way of using recursion to avoid stack overflow?
This is an attempt to solve problem 107, it works well for their example but runs out of stack space for the problem it self.
//-1 16 12 21 -1 -1 -1 16 -1 -1 17 20 -1 -1 12 -1 -1 28 -1 31 -1 21 17 28 -1 18 19 23 -1 20 -1 18 -1 -1 11 -1 -1 31 19 -1 -1 27 -1 -1 -1 23 11 27 -1
public class tries
{
public static int n=7,min=Integer.MAX_VALUE;
public static boolean[][] wasHere=new boolean[n][60000];
public static void main(String[] args)
{
int[] lines=new int[n]; Arrays.fill(lines, -1000); lines[0]=0;
int[][] networkMatrix=new int[n][n];
Scanner reader=new Scanner(System.in);
int sum=0;
for(int k=0; k<n; k++)
{
for(int r=0; r<n; r++)
{
networkMatrix[k][r]=reader.nextInt();
if(networkMatrix[k][r]!=-1) sum+=networkMatrix[k][r];
Arrays.fill(wasHere[k], false);
}
}
recursive(lines,networkMatrix,0,0);
System.out.println((sum/2)-min);
}
public static void recursive(int[] lines, int[][] networkMatrix, int row,int lastRow)
{
wasHere[row][value((int)use.sumArr(lines))]=true;
if(min<sum(lines)) return;
if(isAllNotMinus1000(lines)) min=sum(lines);
int[][] copyOfMatrix=new int[n][n];
int[] copyOfLines;
for(int i=0; i<n; i++)
{
copyOfLines=Arrays.copyOf(lines, lines.length);
for(int k=0; k<n; k++) copyOfMatrix[k]=Arrays.copyOf(networkMatrix[k], networkMatrix[k].length);
if(i!=0&&copyOfMatrix[i][row]!=0) copyOfLines[i]=copyOfMatrix[i][row];
copyOfMatrix[i][row]=0; copyOfMatrix[row][i]=0;
if(networkMatrix[row][i]==-1) continue;
if(wasHere[i][value((int)use.sumArr(copyOfLines))]) continue;
if(min<sum(copyOfLines)) continue;
recursive(copyOfLines,copyOfMatrix,i,row);
}
}
public static boolean isAllNotMinus1000(int[] lines)
{
for(int i=0; i<lines.length; i++) {if(lines[i]==-1000) return false;}
return true;
}
public static int value(int n)
{
if(n<0) return (60000+n);
return n;
}
public static int sum(int[] arr)
{
int sum=0;
for(int i=0; i<arr.length; i++)
{
if(arr[i]==-1000) continue;
sum+=arr[i];
}
return sum;
}
}
why does recursion cause stackoverflow so much more than loops do
Because each recursive call uses some space on the stack. If your recursion is too deep, then it will result in StackOverflow, depending upon the maximum allowed depth in the stack.
When using recursion, you should be very careful and make sure that you provide a base case. A base case in recursion is the condition based on which the recursion ends, and the stack starts to unwind. This is the major reason of recursion causing StackOverflow error. If it doesn't find any base case, it will go into an infinite recursion, which will certainly result in error, as Stack is finite only.
In most cases, a stack overflow occurs because a recursive method was ill-defined, with a non-existent or unreachable ending condition, which causes the stack memory space to be exhausted. A correctly written recursion should not produce a stack overflow.
However, there are situations where a method can produce a stack overflow even if it was correctly implemented. For instance:
A fast-growing (say, exponential) recursion. For example: the naive recursive implementation of the Fibonacci function
A very big input data, that will eventually cause the stack space to be exhausted
Bottom line: it all depends on the particular case, it's impossible to generalize regarding what causes a stack overflow.
Each recursive call uses some space on the stack (to house anything specific to that one call, such as arguments, local variables, etc.). Thus, if you make too many recursive calls (either by not correctly providing a base case or just by trying to do too many recursive calls), then there is not enough room to provide space for it all, and you end up with a StackOverflow.
The reason why loops do not have this problem is that each iteration of a loop does not use its own unique space (i.e. if I loop n times, I don't need extra space to do the n+1st loop).
The reason why the recursion causes stack overflow is because we fail to establish when the recursion should stop, and thus the function/method will keep calling itself "forever" (until it causes the error). You will have the same problem even if you are using loops, if you have something as the following:
bool flag = true;
while (flag == true){
count++;
}
Since flag will always be true, the while loop will never stop until it gives you the stack overflow error.
Every level of recursion that you go down, you are add state information to the runtime stack. This information is stored in an activation record and contains information like which variables are in scope and what their values are. Loops do not have extra activation records each time you loop so they take less memory.
In certain situations your recursion may go deep enough that it causes the stack to overflow but there are ways to help prevent this from happening. When working with recursion, I usually follow this format:
public obj MyMethod(string params) {
if (base-case) {
do something...
} else {
do something else...
obj result = MyMethod(parameters here);
do something else if needed..
}
}
Recursion can be super effective and do things that loops cannot. Sometimes you just get to a point where recursion is the obvious decision. What makes you a good programmer is being able to use it when it is not completely obvoius.
When properly used, recursion will not produce a StackOverflowError. If it does, then your base case is not being triggered, and the method keeps calling itself ad infinitum. Every method call that does not complete remains on the stack, and eventually it overflows.
But loops don't involve method calls by themselves, so nothing builds up on the stack and a StackOverflowError does not result.
Every time you call a method, you consume a "frame" from the stack, this frame is not released until the method returns, it doesn't happen the same with loops.
recursion causes stack overflow cause all the previous calls are in memory. so your method calls itself with new parameters, then that again calls itself. so all these calls stack up and normally can run out of memory.
loops store the results normally in some variables and call the methods which is like a new fresh call to methods, after each call, the caller methods ends and returns results.
As in my opinion, getting error as StackOverFlow in Recursion due to :
not implemented the recursion correctly which results in infinite recursion, so check out the base case, etc.
If your input is large, it preferred to use Tail Recursion to avoid StackOverflow.
Here for loop is used inside the recursive function. When the recursive function is called, for(int i=0; i<n; i++) the value of i is initialized to zero, as it calls itself, the value of i will again be initialized to zero and it conitues infintely. This will lead you to Stack overflow error.
Solution: Avoid for loop inside recursive function; instead go for while or do-while and initialize the value of i outside recursive function

Factorial of a number using recursion

I have the below recursive function to compute factorial of a number. The program works fine except when I remove the if condition. Can someone explain why?
This is the code that works fine --
public static long factUsingRecursion(int number) {
if (number == 1) {
return 1;
} else {
return number * factUsingRecursion(number - 1);
}
}
Without the if condition (Code that throws the error),
public static long factUsingRecursion(int number) {
return number * factUsingRecursion(number - 1);
}
I get the stack overflow error.
Exception in thread "main" java.lang.StackOverflowError
at birst.FactorialUsingRecursion.factUsingRecursion(FactorialUsingRecursion.java:10)
Request experts to please advise me why this is the case?
In recursion, there must always be a base case that stops the recursion. Without the if, you have no base case and nothing stops it. Eventually too many method calls are on the stack and a StackOverflowError results.
This line causing number variable to be decreased by 1
return number * factUsingRecursion(number - 1);
and it will handle all values of number except when it is 1
so this line of code is a break condition
if (number == 1) {
return 1;
}
and it prevent you to avoid stackoverflow exception
Recursion requires a base case. Without it, it will continue calling the function over and over and never stop. The if statement is the base case, which terminates the recursion. That is why if you remove it, you get a StackOverflowError.
Imagine what happens when you call:
factUsingRecursion(3);
With the if:
3*factUsingRecursion(2)
3*2*factUsingRecursion(1)
3*2*1
Without the if:
3*factUsingRecursion(2)
3*2*factUsingRecursion(1)
3*2*1*factUsingRecursion(0)
3*2*1*0*factUsingRecursion(-1)
3*2*1*0*-1*factUsingRecursion(-2)
3*2*1*0*-1*-2*factUsingRecursion(-3)
...
And so on... It will not stop until you encounter the StackOverflow error
It loses one of the things that makes a recursive function recursive in that it has no exit condition.
All recursive solutions must satisfy three rules or properties:
A recursive solution must contain a base case.
A recursive solution must contain a recursive case.
A recursive solution must make progress toward the base case.
From: Data Structures and Algorithms Using Python
The program will no longer work when you remove the if condition because you will just be left with return number * factUsingRecursion(number - 1); and the factUsingRecursion(number - 1) here would have the same return calling return number * factUsingRecursion(number - 1);. Your function constantly calls itself, never able to evaluate to anything. By setting the condition, you function is able to evaluate to a definitive value at some point in the recursive chain, and the first call can evaluate.
For every integer i, you are calling the function with i -1. Integersa are infinite, so you would never stop calling the function. eg: -1000 would call -1001 and this would keep going as long as JVM has some space in it's stack.

Categories

Resources