Not able to understand this recursion - java

The input is {4,7,3,6,7} and The output is:
[81]
[40, 41]
[21, 19, 22]
[11, 10, 9, 13]
[4, 7, 3, 6, 7]
The recursive program I have for this is below, where I have added some print statements to understand the recursion:
import java.util.Arrays;
public class triangle_array {
public static void print(int a[])
{
if(a.length==0)
return;
int n=a.length;
int newa[]=new int[n-1];
for(int i=0;i<n-1;i++)
{
newa[i]=a[i]+a[i+1];
}
System.out.println("here1") ;
print(newa);
System.out.println("here2") ;
if(newa.length!=0)
System.out.println(Arrays.toString(newa));
}
public static void main(String args[])
{
int a[]={4,7,3,6,7};
print(a);
System.out.println(Arrays.toString(a));
}
}
I got the output as:
here1
here1
here1
here1
here1
here2
here2
[81]
here2
[40, 41]
here2
[21, 19, 22]
here2
[11, 10, 9, 13]
[4, 7, 3, 6, 7]
I am not able to completely understand this recursion,
From the above here statements, I understand that the print methos is being called recursively first, and when the condition fails, it returns to outside of print and goes to the line and prints "here2" 2 times and it verifies for the length of newa which is zero, until this point I understood, but in the next iterations how does the length of newa increase and how does the below condition become true, for the println statement ?

In general, if there are prints in a recursive method, all the prints that come before the recursive call will be printed in the order of increasing recursion depth, and all the prints that come after the recursive call will be printed in the reverse order.
public static void demoRecursion( int n, int depth ) {
if ( n <= 0 ) {
return;
}
System.out.println( "Before recursive call, depth " + depth );
demoRecursion( n - 1, depth + 1 );
System.out.println( "After recursive call, depth " + depth );
}
If you call this method using demoRecursion( 3, 1 ) you'll get:
Before recursive call, depth 1
Before recursive call, depth 2
Before recursive call, depth 3
After recursive call, depth 3
After recursive call, depth 2
After recursive call, depth 1
So it's not as if a was increasing in size. It's simply that at depth 1, you have a 5 item array, at depth 2, you have a 4 item array, at depth 3, you have 3 and so on.
So because of the reverse printing effect I demonstrated above, each depth`s array is printed after the array of the deeper level, which was shorter.
If you had printed the array before the recursive call, the prints would have been in decreasing order.

You need to think hard to understand it properly.
Since you don't understand how newa's size decreases,I'll explain that part. Firstly,print method is called from main. Then, 1st print starts executing,and creates newa with length 4 and stops at print(newa) while the 2nd print starts.
Then, 2nd print starts executing,and creates newa with length 3 and stops at print(newa) while the 3rd print starts.
Then, 3rd print starts executing,and creates newa with length 2 and stops at print(newa) while the 4th print starts executing.
Then, 4th print starts executing,and creates newa with length 1 and stops at print(newa) while the 5th print starts executing.
Then, 5th print starts executing,and creates newa with length 0 and stops at print(newa) while the 6th print starts executing.
Then, 6th print starts executing, and stops at return; as length is 0 at this point.
The 5th print continues and as the length is 0,it will not print anything.
The 4th print continues and prints newa (length is 1)
The 3rd print continues and prints newa (length is 2)
The 2nd print continues and prints newa (length is 3)
The 1st print continues and prints newa (length is 4)
At last,main prints the whole array.

The length of newa doesn't increase, it always decreases by one. The shortest one gets printed first because the recursive call is before the instruction to print the array. So it says "create the new shorter array, but then recursively handle it (which involves printing) first, then print yourself".
By the way, the way this is structured is kind of weird. Rather than print newa at the end of the print method, I think it would make more sense to print a (without the if around it), and then you also wouldn't need to print in the main method.

Basically the method is repeatedly making the array smaller by summing consecutive elements. For example:
4, 7, 3, 6, 7
|/ |/ |/ |/
11 10 9 13
|/ |/ |/
21 19 22
|/ |/
40 41
|/
81
The way it works is that on each call, it creates a new array that is one element smaller in size called newa, and each element newa[i] is calculated according to the formula newa[i] = a[i]+a[i+1]. Obviously we want to halt sometime, we don't want to keep recursing and get a StackOverFlowException, so we stop when the input array is empty. So, in psuedo-code, the whole thing is
print(a):
if a is empty
escape from function
else
create newa array of length a.length-1
newa[i] = a[i]+a[i+1] //fill the smaller array
print(newa) // print the smaller array

Your function begin by
if(a.length==0)
return;
So the function clearly stop when a is empty, but in that case, it stops when succession of a decreasing finish by giving a 0-length a. So if your original array have 4 entry, the function will call itself 3 times. 5 entry will call 4 times. And so on. And as each call may recall itself, 5 entry will call the functin,n giving an array of 4 entry, wich will give an array of 3 entry, untill an array of a single entry.
int newa[]=new int[n-1];
for(int i=0;i<n-1;i++)
{
newa[i]=a[i]+a[i+1];
}
this is the key: newa[] is one dimension less than a (n-1, and n is length of a). that's why on each line the array size increases by 1 (last called, first printed). This is the piece that provide each time an array smaller.
The for loop simply put on newa the sum of two neighbour value of a.
This is what it will give successively:
[4, 7, 3, 6, 7]
[4+7, 7+3, 3+6, 6+7] --> [11, 10, 9, 13]
[11+10, 10+9, 9+13] --> [21, 19, 22]
[21+19, 19+22] --> [40, 41]
[40+41] --> [81]
The less sized array is displayed first because when you call the function, it will call itself until the smallest array possible. And the structure of print make that the last called is the first printed, as last called function will be the first to finish, the other call won't finish untill the level below doesn't have finished. That's why you thought a was increasing, you must read those kind of function in the reverse order.
Regarding your print in order to debug. The long amount of "here1" is caused by the fact you print this before the function prints it output. That's why you got a lot of here1. then each function call prints it output.
And finally, regarding the last condition:
if(newa.length!=0)
When a is [81], newa will be an array of length 0, it's to ensure you can't print a 0-length array. So this condition is always true untill the last level.
Note that putting print(newa); under that condition and removing the first part that checks a isn't an array of 0 length won't change anything in the function

What would help you to understand would be to remove all println statements and instead put just one System.out.println(Arrays.toString(newa)) at the very start of the print method. The triangle will be inverted and it will make more sense.

Related

Why is there a "0" value remaining in the list, despite code that removes "0" values?

I am working through sample questions for the Computer Science A exam and cannot figure out why the correct answer is correct on the following problem.
Consider the following method.
public static void mystery(List<Integer> nums)
{
for (int k = 0; k < nums.size(); k++)
{
if (nums.get(k).intValue() == 0)
{
nums.remove(k);
}
}
}
Assume that a List values initially contains the following Integer values.
[0, 0, 4, 2, 5, 0, 3, 0]
What will values contain as a result of executing mystery(values)?
The correct answer showing is : [0, 4, 2, 5, 3]
Why does the first 0 remain in the list?
The first 0 remains because that was really the second 0 in nums.
When k is 0, the test succeeds and remove(0) is called, removing the first index. That shifts all the other elements down, so that the list is now [0, 4, 2, 5, 0, 3, 0]. But then k is incremented to 1, so the second 0 (now at index 0) is skipped and not removed.
The other 0 values are removed successfully, just as the first 0 is removed successfully. This code skips only the second of two consecutive 0 values. This would be a bug, assuming that the code is supposed to remove all 0 values.
The answer already given by #rgettman is correct. However, I'd like to add that this is a particular example of a common issue - that of modifying a sequence (collection, whatever) while iterating (indexing, whatever) through it. You need to understand the effect that the modification will have on the in-progress iteration. And sometimes the effect is formally given as "undefined", i.e., you don't want to do it.
For Java, the Iterator<> class has a remove() method that safely removes the current element. If you actually wanted to remove all zeroes from your List<>, rather than just explaining what is happening in the test question, then Iterator would be one way to go about it.

Created almost working sort algorithm but I don't understand the second for-loop

This is what I coded myself and I understand everything what is done here:
import java.util.Arrays;
public class Decision{
public static void main (String[]args){
int[] myArray = {1,8,3,0,2};
for(int i=0; i<myArray.length-1; i++){
if(myArray[i]<myArray[i+1]){
}
else{
int temp=myArray[i];
myArray[i]=myArray[i+1];
myArray[i+1]=temp;
}
System.out.println(Arrays.toString(myArray));
}
}
}
Output: [1, 3, 0, 2, 8]
So we first check if the first value in the array is smaller than the next one. If yes, then don't do anything. If not, then swap both.
The problem with this sort algorithm is that it won't swap as example the first value with the third one, or the second with the fifth, etc.
I realized this sort works perfectly if we add a second for-loop that repeats the for-loop in my code:
for(int n=myArray.length; n>1; n=n-1){
...
}
I also realized this kind of sort is called bubble sort, but please explain me the important role of this for-loop, I'm sad I cannot understand what it does at all? : /
In all honesty I'm a bit confused about your question. Normally I'd recommend adding diagnostics printouts, but you already have one. As you can see, doing only one pass can at most swap an item with the one next to it. There's no way you can fully sort the array this way, because once you process one element at [i], your algorithm of course can't move that element anywhere else. So if it's not in its final correct position after that one pass, it'll never get there. In particular, a given element can only be moved to the left at most 1 position per pass. The worst case of this is if the input is sorted in decreasing order before going in.
When you add an outer loop doing multiple passes, it sorts the array a little bit more each time, until finally it's sorted. Doing myArray.length - 1 passes guarantees that even the worst-case elements get a chance to be "moved" through the entire array to their correct position, because in the worst case input it guarantees that you'll be able to move an element left through the entire array (in an array of length n it takes n-1 moves to get the element in the last position into the first position -- if this doesn't click, draw it on paper and count).
I mean, there is an important skill missing from your toolset that you really ought to learn, which is that you need to get used to visualizing what your code does. There are a few ways to do this:
Research the algorithm you are implementing. The linked wiki article on bubble sort pretty clearly explains the algorithm in the step-by-step section.
With some experience it will make sense in your head.
Work things out on paper.
Trace through things line-by-line in your debugger.
Add temporary trace print-outs to your programs.
And of course, sometimes experimenting with algorithms by breaking them and observing the changes.
You went with #5 and #6, you just need to learn how to interpret the information. Here is a working version of your sort, for example (ignoring other potential code improvements, I am certain other answers here will help you along those line) with one extra print added to separate the passes in the output:
public static void main (String[]args){
int[] myArray = {1,8,3,0,2};
for(int n=myArray.length; n>1; n=n-1){
System.out.println("Outer loop: " + n);
for(int i=0; i<myArray.length-1; i++){
if(myArray[i]<myArray[i+1]){
}
else{
int temp=myArray[i];
myArray[i]=myArray[i+1];
myArray[i+1]=temp;
}
System.out.println(Arrays.toString(myArray));
}
}
}
This outputs:
Outer loop: 5
[1, 8, 3, 0, 2]
[1, 3, 8, 0, 2]
[1, 3, 0, 8, 2]
[1, 3, 0, 2, 8]
Outer loop: 4
[1, 3, 0, 2, 8]
[1, 0, 3, 2, 8]
[1, 0, 2, 3, 8]
[1, 0, 2, 3, 8]
Outer loop: 3
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
Outer loop: 2
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
As you can see, after the first pass it's not fully sorted. The second pass is a bit closer. The third pass completes it in this case. It's the 0 that's holding things up in this case: The 0 has to move left 3 positions, and so you must complete at least 3 passes.
For an even clearer picture try that ideone example with the worst case input of [8, 3, 2, 1, 0].
Assume the worst case for this algorithm, an array sorted in reverse order and see what happens with one loop
4 3 2 1 0 original array
3 4 2 1 0 after one swap
3 2 4 1 0 after two swaps
3 2 1 4 0 after three swaps
3 2 1 0 4 after the complete loop
You see that only the largest element is now in the right place, all the rest is still in reverse order. After a second pass the second largest element will be in the correct place as well and so on.
Note that the passes after the first do not have to go over the full array (but it does not hurt) because more and more elements will already have reached their final position.
Instead of adding the 2nd loop you could also say
boolean change = true;
while (change) {
change = false;
...
if (a[i] > a[i + 1]) { // write it like this and you don't need an else
change = true;
// swap
}
...
}
Both work, because the maximum number of passes needed to sort the array is n - 1. For the worst case, an array sorted descending instead of ascending, the elements will wander to the end like water bubbles to the top of the water. On the first iteration the first element will end up in the last position, on the 2nd iteration the originally 2nd element (now first) will travel up to the 2nd last position and so on. So you can see that you need only n-1 iterations, because on the (n-1)th iteration the originally 2nd last element (now the first) will end up in 2nd position and the originally last element (now the first) is already sorted correctly.
You can also notice, that on each iteration (at least) one more element at the end of the array ends up in its correct position, so you can decrease the max for the inner loop on each iteration.

Unable to stop the recursion at certain condition

I am doing string (i.e. char array) processing with recursion. In my recursion tree, string located at child has length less than 1 w.r.t its parent and all children at the same height have same length of string but different characters. I want to stop the recursion whenever new string length is greater than or equal to old string length, but i am unable to insert this condition in between recursion. Using System.exit(0) terminates my complete program, which i don't want. Below is my code snippet-
private static void getMinLen(char[] oldStr) {
int len = oldStr.length;
/*
* This terminates the whole program, using break in place of
* System.exit(0) is not effective
*/
if (len < 2)
System.exit(0);
char[] newStr = new char[len - 1];
for (int i = 0; i < len - 1; i++) {
/*
* Every character is matched with its next character and a new char
* array is created having length (len-1)
*/
getMinLen(newStr);
}
}
Actually when i put System.out.println("length=" + len); in the 3rd line. First it prints the length in decreasing order but then length increases, decreases because of recursion. I mean the console shows the following-
length=6
length=5
length=4
length=3
length=2
length=1
length=3
length=3
length=2
length=1
length=4
length=3
length=2
length=1
I simply want to stop my recursion whenever new length becomes greater than or equal to old length.
In every call to getMinLen(oldStr) where the stop condition is not satisfied, you call getMinLen(newStr) several times (in fact as many times as there are elements in newStr). It is not clear from your question or your first comment whether this is intentional. (The fact that your newStr has as many elements as your loop has iterations may suggest it is not.)
If this is not intentional, just move the recursive call one line down, i.e. behind the closing } of the loop.
If it is intentional, the problem may be that you have not understood how recursion works. The fact that the stop condition is fulfilled somewhere is not recorded globally and only relevant for the single call in which the stop condition is fulfilled. This point was itself reached by a recursive call getMinLen's for loop (unless you start with a very short string), and that (outer) for loop continues to execute all subsequent calls to getMinLen--why should it stop? To make it stop, a global boolean variable would help, but be very inelegant. Alternatively, you could make the function return a boolean value and check before each recursive call whether a previous one returned true. You may also, however, reconsider whether a recursive approach is really the most suitable for the problem.
Just replace System.exit(0); by return; at the line you want to exit your method
You should use return.
if (len < 2)
return;
Note that break does only "break" loops or switch statements. To leave a method you have to reach the return statement or end of the method (which acts as an implicit return statement in case the return type is void).
Note that your method does the following:
Assume the initial length is 4:
1. create a new array of length 3 (4-1)
2. call the method recursively 3 times with an array of length 3
3. each new call creates an array of length 2 (3-1)
4. call the method recursively again, now 2 times and with an array of length 2
5. each new call creates an array of length 1 (2-1)
6. call the method recursively again, now once and with an array of length 1
7. each new call creates an array of length 0 (1-1)
8. those methods won't enter the loop since the condition now is `i < 0`, which is false with `i = 0`
Thus, when printing each length, I'd expect the following output
4 //initial call
3 //first iteration of step 2
2 //first iteration of step 4
1 //only iteration of step 6
2 //second iteration of step 4
1
3 //second iteration of step 2
2
1
2
1
3 //third iteration of step 2
2
1
2
1
If you just want one iteration and then stop, why did you put the loop in there?

How does this implementation of Fibonacci(n) work? [recursion]

Theres an exercise from a Java book I'm reading that has me confused:
A Fibonacci sequence is the sequence of numbers 1, 1, 2, 3, 5, 8,
13, 21, 34, etc., where each number (from the third on) is the sum
of the previous two. Create a method that takes an integer as an
argument and displays that many Fibonacci numbers starting from the
beginning. If, e.g., you run java Fibonacci 5 (where Fibonacci is
the name of the class) the output will be: 1, 1, 2, 3, 5.
I could have swore that it would need an array or some way of storing the previous numbers but when I saw the answer it wasn't the case:
import java.util.*;
public class Fibonacci {
static int fib(int n) {
if (n <= 2)
return 1;
return fib(n-1) + fib(n-2);
}
public static void main(String[] args) {
// Get the max value from the command line:
int n = Integer.parseInt(args[0]);
if(n < 0) {
System.out.println("Cannot use negative numbers"); return;
}
for(int i = 1; i <= n; i++)
System.out.print(fib(i) + ", ");
}
}
Would someone be able to explain how using a function within itself produces this?
The code you gave is an example of a recursive solution. When the function is called for the first time, it executes until it calls itself. Its state is stored on the stack, and the code begins executing again with new input data. This process repeats until the input is less than 2, at which point 1 is returned, and the answer returns to the previous caller.
For example, calling fib(5) results in the following execution:
fib(5):
fib(4):
fib(3):
fib(2): 1
fib(1): 1
fib(2): 1
fib(3):
fib(2): 1
fib(1): 1
Note that you are partially correct. Intermediate results are stored on the stack in this solution. That is one of the reasons why the recursive solution is so expensive. The other is its O(2^n) complexity. However, if is possible to compute Fibonacci(n) iteratively and without storing all previous results. All you really need is to store the last to results and count from 1 up to n.
This is a recursive solution. A recursive function calls itself until a given stop condition is met. Then each call exits until only the first call remains. That first call outputs the result.
In your solution, the stop condition is :
if (n <= 2)
return 1;
until this condition is met, the function will make successive calls to itself. Each call reduces the int passed as a parameter. When it reaches 2, the stop condition dictates that the function returns with value 1 (the result of n=1 and n=2 in fibonacci(n) ).
Because the fibonacci is the sum of the last two numbers, the recursive part of the function,
return fib(n-1) + fib(n-2);
does a sum of n-1 and n-2 (as I said, the two last numbers of the sequence). When the n equals 2, these calls to function fib will finally have a value, and will be returned.
Example, if n = 3, the recursive part will call fib(2) and fib(1), both are equal or less than 2, so both calls will return 1. So the printf will print 1, 1, 2.
2 is the sum of 1 + 1 (I know it's obvious, but sometimes stating the obvious helps).
F(n)
/ \
F(n-1) F(n-2)
/ \ / \
F(n-2) F(n-3) F(n-3) F(n-4)
/ \
F(n-3) F(n-4)
Important point to note is this algorithm is exponential because it does not store the result of previous calculated numbers. eg F(n-3) is called 3 times.
For more details refer algorithm by dasgupta chapter 0.2
This is the standard example for an recursive function.
The Fibonacci Numbers are declared recursive, too.
Both fib(1) and fib(2) are declared as 1. All others are calculated by adding the last two fibonacci numbers, so fib(3)=fib(2)+fib(1).
Compare this to the calculation method which does exactly this:
static int fib(int n) {
if (n <= 2)
return 1;
return fib(n-1) + fib(n-2);
}
By the way, this is a very slow way to calculate the fibonacci numbers, using two variables (you don't need all of them for the last one, only the last two!) and a loop is in O(n), the recursive function above has O(2^n) operations.

Java Homework Help - Recursion with array

I've got a set of recursion problems that I need to do. I've completed 3 out of the 4 of them we were given, but I'm having a hard time wrapping my head around this last one. I don't necessarily want the actual answer, but maybe just point me in the right direction, because I'm not even seeing what my stop condition should be on this one. And note, it has to be recursive, no loops, etc.
Thanks in advance for any help provided!
Write recursive method arrayRange that returns the maximum integer minus the minimum integer in the filled array of ints. Use recursion; do not use a loop. The following assertions must pass (note the shortcut way to pass a reference to a new array--it saves your writing a bit of code (this passes an array built as a parameter):
assertEquals(2, rf.arrayRange(new int[] { 1, 2, 3 } ));
assertEquals(2, rf.arrayRange(new int[] { 3, 2, 1 } ));
assertEquals(0, rf.arrayRange(new int[] { 3 } ));
assertEquals(3, rf.arrayRange(new int[] { -3, -2, -5, -4 } ));
// Precondition: a.length > 0
public int arrayRange(int[] a)
The stop condition is when there are only two items left: the maximum and minimum. Then just return the difference. (Also handle the case of 1 or 0 items, consider input such as in the test cases.)
Now .. how to reduce the list each pass? :) I would consider inspecting the first three values at a time (of the three, only two should remain in the recursive step).
Happy homeworking.

Categories