+ All Categories
Home > Documents > Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections...

Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections...

Date post: 14-Oct-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
39
CS 1302 – Chapter 18 Recursion These notes cover Sections 18.1-18.5, 18.9-18.10 Section 18.1 – Introduction 1. A recursive method is one that calls itself. As shown on the right, the recursivePrint method calls itself. 2. Recursion is a problem solving technique that is a form of repetition; however, no loop is involved – instead, a recursive method is employed. 3. The method above is not particularly useful, nor is it a good use of recursion. However, it is easy to understand and we use it (and subsequent variations that follow) to understand how recursion works. Later we will examine problems where recursion is a natural and useful problem solving technique. 4. Example 1 – Consider calling the method above with n=2 as shown below (the name of the method has been shortened to recurPrint). Follow the numbered steps in purple: 1
Transcript
Page 1: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

CS 1302 – Chapter 18Recursion

These notes cover Sections 18.1-18.5, 18.9-18.10

Section 18.1 – Introduction

1. A recursive method is one that calls itself. As shown on the right, the recursivePrint method calls itself.

2. Recursion is a problem solving technique that is a form of repetition; however, no loop is involved – instead, a recursive method is employed.

3. The method above is not particularly useful, nor is it a good use of recursion. However, it is easy to understand and we use it (and subsequent variations that follow) to understand how recursion works. Later we will examine problems where recursion is a natural and useful problem solving technique.

4. Example 1 – Consider calling the method above with n=2 as shown below (the name of the method has been shortened to recurPrint). Follow the numbered steps in purple:

Notes about the execution:

The output of this method is: 2 1

1

Page 2: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

This method recurses in Steps 3 and 5. The term recurse is also referred to as winding, and is used to describe the process of a recursive method calling itself over and over.

At Steps 2, 4, and 6 a check is made to see if the recursion should continue. This check is called a stopping rule. A recursive method must have a stopping rule otherwise the recursion would continue indefinitely.

At Step 6, n=0 and the recursion stops, the method ends and control returns to the calling method (Step 7). The calling method method has no more code to execute, so control returns to its calling method (Step 8) and finally control returns to main (Step 9) and the program ends. This process is called unwinding. The term unwind refers to the process of one method ending and returning to the method that called it.

Notice that the printing took place during the winding and that no real processing (i.e. no printing, etc.) took place during the unwinding, though it can as in the next example.

What would the method produce if we call it with n=4?

5. Example 2 – Next, we move the print statement in the previous example to after the recursive call as shown on the right.

Consider calling this method with n=2 as shown below. Follow the numbered steps in purple:

Notes about the execution:

The output of this method is: 1 2 The printing took place during the unwinding. The calling method retains its own value of n. For example, at Step 6, n=0 and at Step 7 we unwind to

the calling method where n=1. 2

Page 3: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

What would the method produce if we call it with n=4?6. Example 3 – The example on the right looks very

similar to the previous one. The only difference is:

recursivePrint( n-1 ); // Example 2

recursivePrint( --n ); // Example 3

In both cases a recursive call is made passing a value 1 less than n. The difference is that “--n” changes the value of n in the current invocation of the method. Consider calling this method with n=2 as shown below. Follow the numbered steps in purple:

Notes about the execution: The output of this method is: 0 1 This version (Example 3) also does the printing during the unwinding but notice that each invocation of

the method changes the value of n. For example at Step 1, we enter the method with n=2 but then just before we take Step 3 (the recursive call), n is changed to 1. Thus, during the unwinding at Step 8, we print 1.

What would the method produce if we call it with n=4?

3

Page 4: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

7. Call Stack Example – The figure below shows main calling recursivePrint (Example 1) with the value 2. The figure shows exactly how the stack grows and shrinks as the code executes. Take your time and study the code below carefully and verify the numbered (purple) steps below.

1. recurPrint(2) is called, a frame is pushed onto the stack, and since n=2>0, “2” is printed2. recurPrint(1) is called, a frame is pushed onto the stack, and since n=1>0, “1” is printed3. recurPrint(0) is called, a frame is pushed onto the stack, and since n=0, the method ends4. As the method ends, the stack is popped and execution resumes in the caller (in this case the caller

has no more code to execute).5. Same as 4.6. Same as 4.

8. A recursive definition refers to a situation where something is defined in terms of itself. Examples:

a. The recursive definition of factorial is: n !=n∗(n−1 ) ! where 0 !=1 for n≥0b. Exponentiation can be defined recursively: xn=x∗xn−1c. The Koch snowflake

4

Page 5: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Source: http://en.wikipedia.org/wiki/Recursive_definition9. Some problems are naturally recursive:

a. Example – If someone asked you to find a particular file in a folder on your hard drive, you would look in that folder. If you didn’t see it, you would look in each subfolder. And, if still not found, you’d continue to look in sub-subfolders. A recursive algorithm (pseudo-code) for the problem is shown below. The recursive step is highlighted in yellow.

lookForFile( folder, fileName )folderItems = folder.getItemsInFolder()for( item : folderItems )

if( item isA File )if( item.fileName = fileName )

Return itemelse if( item isA Folder )

lookForFile( item, fileName )

b. Example – Consider a maze as shown on the right where you enter where the red arrow is and try to find a path to the exit (green arrow). To solve this with a recursive algorithm we would model the maze as composed of a bunch of square rooms. Each room has 4 sides, some of which are walls and can’t be crossed and other are doors which can be crossed. This is the basic idea of a recursive algorithm to solve this problem:

findPath( room )if room is destination

found = truefor( side : room.sides() )

if( !found && side isA Door )findPath( room.side().nextRoom() )

5

Page 6: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

1. Consider recursivePrint which we considered earlier (Example 1, shown below). It doesn’t appear to have a stopping condition.

private static void recursivePrint(int n) {if( n > 0 ){

System.out.print( n + " ");recursivePrint1(n-1);

}}

It actually does have a stopping condition, it is just subtle. We see that every recursive call reduces n by 1. What happens when n=0? The method simply ends. Thus, the stopping condition is implicit. We could have written recursivePrint as shown below with an explicit base case and it would operate identically.

Section 18.3 – Problem: Computing Fibonacci Numbers

1. A Fibonacci number can be recursively defined as:

F (n )=F (n−1 )+F (n−2 ) forn≥2, where F (0 )=0 , F (1 )=1.

Examples:

F (0 )=0 F (1 )=1 F (2 )=F (1 )+F (0 )=1+0=1

F (3 )=F (2 )+F (1 )=¿ (F (1 )+F (0 ) )+1=¿ (1+0 )+1=2

F (4 )=F (3 )+F (2 )=¿ (F (2 )+F (1 ) )+ (F (1 )+F (0 ) )=¿ [ (F (1 )+F (0 ) )+F (1 ) ]+(F (1 )+F (0 ) )=¿1+0+1+1+0=3

F (5 )=F (4 )+F (3 )=3+2=5 F (6 )=F (5 )+F (4 )=5+3=8 etc .

6

Page 7: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

2. Below we show a method to calculate the Fibonacci number for a given input using a recursive approach. Note that there are two base cases:

3. Using recursion to calculate a Fibonacci number is not efficient. We are repeatedly calling Fibonacci on the same values. Consider, a trace of the recursive calculation of fibonacci(5)

Note that we have called fib(3) twice, fib(2) 3 times, and fib(1) 5 times, etc.

We should never use recursion when we duplicate work by solving the same instance of a problem in separate recursive calls.

Fun Fact: For n≥3 it can be proved that the number of calls to fib(n) is larger than the actual Finonacci number itself! For instance, when n=40, F (40 )=102,334,155 and the total number of recursive calls is more than 300,000,000. This is particularly ridiculous considering an iterative approach would take just 40 iterations of a loop! We say this recursive algorithm has an exponential number of recursive calls. In other words, the number of recursive calls grows exponentially as n increases. The graph on the right shows the time it took to compute Fibonacci(n) on my computer using a recursive algorithm. The time for an iterative approach is effectively 0.

7

0102030405060

40 41 42 43 44 45 46 47 48 49 50

Tim

e(se

c)

n

Page 8: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Section 18.4 – Problem Solving using Recursion

1. All recursive methods have the following characteristics:

a. There is an if/else or switch statement that leads to different cases.b. One or more base cases are used to stop the recursion.c. Every recursive call creates a smaller version of exactly the same problem bringing it increasingly closer to a

base case until it becomes that base case (stopping the recursion).

To solve a problem using recursion the key is to break the problem into sub-problems where the sub-problems are identical to the original problem, except smaller in size.

2. Palindrome Example – We remember that a string is a palindrome if it reads the same forwards and backwards. Consider a method, isPalindrome that accepts a string and returns true if the string is a palindrome and false otherwise.

a. An idea for a recursive algorithm to solve the problem is shown on the right. The idea is:

Base Case:If the first and last characters are different, return false

Make the problem smaller (recursive step):If the first and last characters are the same, remove them and then ask if the remaining string is a palindrome.

b. However, we need another base case, one that returns true when we have exhausted all the characters. For example, in the example above, we check: “c and c”, then “o and o”, then “w and w”. Finally, there is just one character left, “o”. Of course, a single character is a palindrome. Thus, another base case is:

If the string has only one character, return true.

c. This example had use a string whose length was odd. How would this approach work if the string had an even length? Consider, “cowwoc”. The algorithm would check: “c and c”, then “o and o”, then “w and w” which would leave an empty string. Thus, we need another stopping rule:

If the string is empty, return true.

d. Implementation:

public static boolean isPalindrome(String s) {if(s.length() <= 1 ) // base case

return true;else if( s.charAt(0) != s.charAt(s.length()-1 )) // base case

return false;else

return isPalindrome(s.substring(1,s.length()-1));}

8

Page 9: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Homework

1. Write a recursive method, printString that accepts a string and an integer. The method should print the string the number of times specified by the integer.

Problem 2 is similar to a homework problem.

2. Write a recursive method, sumInts that accepts an integer and returns the sum of the integers from 1 to the input integer. For example: sumInts(4)=10 (i.e. 4+3+2+1)

3. Write a recursive method, isPalindrome that accepts a string and returns whether it is a palindrome or not. 4. Write a recursive method to compute the factorial of an input integer.5. Write a recursive method to compute the Fibonacci number of an input integer.

Problems 6,7,8 are similar to a homework problem.

6. Problem 18.4 from text. Write a recursive method to compute the following series:

m (i )=1+ 12+ 13+…+ 1

i7. Problem 18.5 from text. Write a recursive method to compute the following series:

m (i )=13+ 25+ 37+ 49+ 511

+ 613…+ 1

2i+18. Problem 18.6 from text. Write a recursive method to compute the following series:

m (i )=12+ 23+…+ 1

i+1

9. Problem 18.8 from text. Write a recursive method that accepts an integer and displays it reversely on the console. For example: reverseDisplay(12345) displays 54321. Hint: (a) what is the value of 12345%10? (b) what is the value of 12345/10?

10. Write a recursive method, reverseString that accepts an integer and returns a string with the digits of the input integer in reverse. For example: reverseString(8452) returns “2548”. Hint: similar to problem 18.8 except that you need to build the string as you recurse.

11. (omit, hard) Write a method, reverseInt that accepts an integer and returns an integer with the digits of the input integer in reverse. For example: reverseInt(8452) returns 2548. Hint: As you extract each digit you need to multiply it by the appropriate power of 10. For example if 143 is the input, at the first iteration, you extract 3 and then need to multiply it by 10 raised to the 2 power. At the next step, you extract the 4 and multiply it by 10 raised to the 1 power. Note that you can get the exponent with this expression: (int)Math.log10(n).

Problem 12 is similar to a homework problem

12. Problem 18.9 from text. Write a recursive method that accepts a string and displays the string reversely on the console. For example: reverseDisplay(“abcd”) displays: “dcba”.

Problem 13 is similar to a homework problem

13. Write a recursive method that accepts a string and and a character. The method should return the number of occurrences of the character in the string. For example, count(“tree house”,’e’) returns 3.

14. Problem 18.11 from text. Write a recursive method that accepts a long and returns the sum of the digits in the long. For example, sumDigits(83197) returns 28.

9

Page 10: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

10

Page 11: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Section 18.5 – Recursive Helper Methods

1. Recursive Helper Method – Many times when recursion is the desired solution, the actual recursion takes place in a helper method. The helper method usually has at least one additional parameter that describes how far the recursion has already proceeded or how far it still has to proceed and/or a partial computation. Typically, a non-recursive (public) method (meant to be called by users) will call a recursive helper (private) method with the appropriate initial values for the extra parameters.

2. Palindrome Example –

a. As we remember, the String class is immutable and thus the substring method we used in the isPalindrome method in the previous section creates a new (smaller) string with each recursive call. As we recurse, each of these strings is pushed on to the stack. Thus, as the stack grows, more and more strings are being held in memory. If in doubt, run the previous code through the Visualizer and you will see these strings on the stack. http://cscircles.cemc.uwaterloo.ca/java_visualize/. This would be inefficient if input string is very long.

b. Consider another approach where we use indices to indicate which characters we are comparing during each recursive call. As shown on the right we never modify the string we are checking and we also include two additional parameters, first and last that specify which two characters we are going to compare. Initially, we consider the first (index 0) and last character (index 6). Since the characters are the same, we move first and last inward to 1 and 5, respectively. Next, since these two characters (‘o’) are the same we move first and last inward again to 2 and 4, respectively. Finally, we get to a point where first and last are point to the same character, ‘o’ which by definition is a palindrome. Thus, this suggests a stopping rule that when first and last are equal, return true (we will have to modify this shortly as it doesn’t handle the case when the input string has even length).

c. The structure of this approach is to define a public method that accepts a string, just as before. However, it calls a recursive helper method:

public static boolean isPalindrome(String s) {if(s.length() <= 1 )

return true;return isPalindrome(s,0,s.length()-1);

}

// Recursive helper methodprivate static boolean isPalindrome(String s, int first, int last) {

if(first==last) // base case – not correct, needs modificationreturn true;

else if(s.charAt(first) != s.charAt(last)) // base casereturn false;

elsereturn isPalindrome(s,first+1,last-1);

}

Notice that there are two base cases: one for detecting that a string is a palindrome and one for detecting that it is not.

11

Page 12: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

d. Our stopping rule above does not work when the input string has an even length. Consider the figure on the right where the input string has an even length. At the third iteration, we check the middle to characters (“ww”). We could develop a stopping rule that would stop there, but it would be a bit more complicated than it first appears. Every time we find that two characters are the same, before recursing, we would need to check if first=last-1 as shown below:

private static boolean isPalindrome(String s, int first, int last) {if(first==last) // base case for odd length string

return true;else if(s.charAt(first) != s.charAt(last)) // base case

return false;else

if(first==last-1) // base case for even length stringreturn true;

elsereturn isPalindrome(s,first+1,last-1);

}

e. However, if we recurse one more time, as shown in the figure on the right we see that first>last which clearly indicates that we are done. Now, if we combine that with the stopping rule for an odd length string we arrive at a single stopping rule: first>=last that takes care of both even and odd length strings as shown below:

private static boolean isPalindrome(String s, int first, int last) {if(first>=last) // base case

return true;else if(s.charAt(first) != s.charAt(last)) // base case

return false;else

return isPalindrome(s,first+1,last-1);}

f. Finally, you might ask why we need two methods: the non-recursive public method and the private recursive helper method. Why not just use the second method? The answer is simple. The user of our method simply wants to know if a string is a palindrome. We wouldn’t want to burden the user with having to also supply two additional arguments (the index of the first and last character) when we can do that very simply with code. In other words, we are hiding the details of the algorithm.

Homework

12

Page 13: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

15. Problem 18.4. Write a recursive method to sum this series forwards: (i)=1+12+ 13+…+1

i . Hint: you need a

helper method like this:

public static double sumSeriesForwards( int n ) {return sumSeriesForwards_Helper( n, 1 );

}

private static double sumSeriesForwards_Helper(int n, int i) {// You write this code

}

Problem 16 is similar to a homework problem.

16. Write a recursive method, sumArray that accepts an array of integers and returns the sum. For example:

int[] vals = {3,6,9,8}System.out.println( sum(vals) ) // displays 26

17. Problem 18.12 – Write a method that accepts a string and uses a recursive helper method to display the string reversely and without modifying the input string. Hint: the recursive helper method should accept the string and an index indicating the character to display.

Problem 18 is similar to a homework problem.

18. Write a recursive method that accepts an array of strings and returns the shortest length string in the array. Hint: You need a way to store the current shortest length string between recursive calls. Thus, store the min length string as a parameter in the helper method.

19. Problem 18.14 – Write a recursive method that accepts a string and returns the number of uppercase letters in the string without modifying the string.

20. Problem 18.15 – Write a method that accepts a string and a character and uses a recursive approach to count the occurrences of the character in the string without modifying the string.

21. Problem 18.16 – Write a method that accepts an array of characters and uses a recursive approach to count the number of uppercase characters in the array.

22. Problem 18.17 – Write a method that accepts an array of characters and a character, c. The solution should use a recursive approach to count the number of occurrences of c in the array.

3. printFolder Example

Consider a method that accepts a folder (File object) and prints the file names and folder names in that folder, recursively.

13

Page 14: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Notice that the base case is a bit fuzzy. The base case is the if block: every time you find a file, you have hit a base case and you return. Otherwise, you recurse into the folder.

If you want to try this yourself, copy the code:

private static void printFolder( File folder ) { if( !folder.isDirectory() ) {

System.out.println( folder.getName() + ":file" ); } else {

System.out.println( folder.getName() + ":folder" );

File[] files = folder.listFiles();

for( File f : files ) { printFolder( f );

} }}

4. getFiles Example

a. Consider a related problem: write a method that accepts a folder name and returns a list of only File objects that are files (not folders), recursively.

b. Let’s call this new method getFiles and we should see that it is going to return a list of File objects. Thus, the signature will look like this:

public static ArrayList<File> getFiles( File folder ) {

c. We will use the printFolder method above as the basis to construct this new algorithm. Consider the (incorrect) solution below.

private static ArrayList<File> incorrectGetFiles( File folder ) {ArrayList<File> files = new ArrayList<>();

14

Page 15: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

if( !folder.isDirectory() ) {files.add(folder);return files;

}else {

File[] localFiles = folder.listFiles();

for( File f : localFiles ) {incorrectGetFiles( f );

}return files;

}}

The problem with this approach is that we are creating a new ArrayList every time we make a recursive call. For instance, when the if statement is true (i.e. you have a file, not a folder) you add this file to the list and return. However, you return to the else block of the calling method, which has an entirely different (empty!) list. This method will always return an empty list!

15

Page 16: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

d. The problem would be easy if there was one list that was created by a getFiles method and passed to a getFiles helper method. Thus, the public getFiles would look like ths:

public static ArrayList<File> getFiles( File folder ) {ArrayList<File> files = new ArrayList<>();getFiles( folder, files );return files;

}

Since files is a reference variable we can add File objects to it in the helper method. Thus, when the public method (above) is complete, files will contain all the File objects (that are files). The helper method looks like this:

private static void getFiles( File folder, ArrayList<File> files ) {if( !folder.isDirectory() ) {

files.add(folder);}else {

File[] localFiles = folder.listFiles();

for( File f : localFiles ) {getFiles( f, files );

}}

}

Notice that (a) we no longer need any return statements, (b) the method is private, it is a helper method.

Homework – These are from: http://codingbat.com/java/Recursion-1

23. Problem: changePi – Write a method, changePi that accepts a string and recursively returns a new string where all appearances of "pi" have been replaced by "3.14". Hint, use a StringBuilder and a position as parameters for a recursive helper. And, the StringBuilder methods: substring and replace will be helpful.

24. Problem: array11 – Given an array of ints, compute recursively the number of times that the value 11 appears in the array. Thus, the method should have this signature:

public static int array11(int[] nums) {

25. Problem: array220 – Given an array of ints, compute recursively if the array contains a value such that the next value in the array is that value times 10. For example: [4,8,12,15,29] is false and [4,8,12,120,40,400] is true.

26. Problem: allStar – Given a string, compute recursively a new string where all the adjacent chars are now separated by a "*".

allStar("hello") → "h*e*l*l*o"allStar("abc") → "a*b*c"allStar("ab") → "a*b"

27. Example: What does the code below display when it is called with: recur(3)?

private static void recur(int val) {System.out.print(val);if(val>1) {

16

Page 17: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

--val;recur(val);

}System.out.print(val);

}

28. Example: What does the code below display when it is called with: recur2(3)?

private static void recur2(int val) {System.out.print(val);if( val > 1 ) {

recur2(val-1); }

System.out.print(val);}

Section 18.5 – Recursive Helper Methods (cont’d), Selection Sort

1. Sorting means to put the items in a list in order where order is determined by implementing Comparable, Comparator, or relying on the natural ordering for primitive types. Of course we can sort a list using Collections.sort (or Arrays.sort); however, in this section we study how a particular sort method, selection sort works. Sorting is one of the most studied algorithms in computer science:

Sorting Algorithms: https://en.wikipedia.org/wiki/Sorting_algorithm Visual Animations: https://www.toptal.com/developers/sorting-algorithms/ Auditory Animations: https://www.youtube.com/watch?v=t8g-iYGHpEA Hungarian Folk Dance – Quick Sort: https://www.youtube.com/watch?v=ywWBy6J5gz8 Pancake Sorting: https://en.wikipedia.org/wiki/Pancake_sorting In Java, Arrays.sort uses Dual-Pivot Quicksort for primitives and Timsort for objects. Collections.sort uses

Timsort.

2. Problem statement: Assume we have an array of n items, indexed from 0 to n-1. We want to sort these items without creating another array. Although we use an array here, the idea is identical if we had used an ArrayList instead.

17

Page 18: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

3. There are many sorting algorithms1. Here, we consider Selection Sort2. An example of how it works is shown below. Suppose we start with an array of 7 integers:

0 1 2 3 4 5 62 9 5 4 8 1 6

a. Find largest value in positions 0-6 (the value 9 at position 1):

0 1 2 3 4 5 62 9 5 4 8 1 6

b. Swap this largest value with the value in position 6:sorted

0 1 2 3 4 5 62 6 5 4 8 1 9

c. Next, find largest value in positions 0-5 (the value 8 at position 4):sorted

0 1 2 3 4 5 62 6 5 4 8 1 9

d. Swap this largest value with the value in position 5:sorted sorted

0 1 2 3 4 5 62 6 5 4 1 8 9

e. Continue this process …

f. Find largest value in positions 0-1 (the value 2 at position 0):sorted sorted sorted sorted sorted

0 1 2 3 4 5 62 1 4 5 6 8 9

g. Swap this largest value with the value in position 1. Now the list is sorted.sorted sorted sorted sorted sorted sorted

0 1 2 3 4 5 61 2 4 5 6 8 9

4. Let’s think about implementing Selection Sort recursively: Here are several key observations:

a. The process of finding the largest is the same for a list of n items as it is for a list of n-1 itemsb. Think about partitioning the list into values that are sorted (the right hand portion of the list) and unsorted

(the left hand portion of the list).c. When we find the largest value and put it in the last position, then the right portion of the list consisting of

the last element only is sorted. Thus, when we find the next largest and put it in the next to last position, then the right portion of the list consisting of the last two elements is sorted and no longer needs to be considered. Etc.

d. When there is only 1 item left in the left hand portion of the list we are done.

1 https://en.wikipedia.org/wiki/Sorting_algorithm 2 https://en.wikipedia.org/wiki/Selection_sort

18

Page 19: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

5. We see from above that we are going to need to keep track of the current starting position of the right hand (sorted) portion of the list. This suggests that we will need a helper method. A recursive helper algorithm might work like this:

Sort( list, endPos )if one item left in list

returnelse

Find largest in list from 0 to endPosSwap largest item with item in endPosSort( list, endPos-1)

And then we could call this helper with:

Sort( list )Sort( list, list.length-1 );

6. We will implement this algorithm assuming the input is an array of integers. It is a little different from the text.

private static void selectSort( int[] vals ) {if( vals.length > 1 )

selectSort( vals, vals.length-1 );}

private static void selectSort( int[] vals, int endPos ) {int maxValue = vals[0];int maxIndex = 0;

// Base case: list is sorted when only 1 element left.if(endPos<1)

return;

// Find maxfor( int i=1; i<=endPos; i++ )

if( vals[i] > maxValue ) {maxValue = vals[i];maxIndex = i;

}

// Swap max with value in endPos.int lastVal = vals[endPos];vals[endPos] = maxValue;vals[maxIndex] = lastVal;

// Recurse with a shorter listselectSort( vals, endPos-1 );

}

Homework:

29. Suppose you have a Person class that implements Comparable. Right now, it implements Comparable to compare Person objects based on their SSN, but in the future this could change. For instance, compareTo may be changed so that it compares based on name. Write selectSort so that it sorts an ArrayList of Person objects

19

Page 20: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

no matter how the compareTo is implemented. Hint: when finding the max, use the compareTo method.

Section 18.5 – Recursive Helper Methods (cont’d), Binary Search

1. Problem – A common task in software systems is to search for an item in a list. The item we are searching for is called the key, which may or may not be in the list. If we find an item in the list that matches the key, then we either return the item, or we return the index of the item (if the list is an index based structure).

2. Brute-force search – If the items in the list are unordered, then there is not much we can do except inspect the items one-by-one looking for the key. This is called a brute-force search or linear search. If a list has n items, in the best case, we find it on the first inspection. In the worst case, we look through all items and don’t find it, or find it in the last position. On average, if the item exists in the list, we find it after n /2 inspections.

3. Binary search – If the items in the list are ordered, then the fastest way to search for a key is to use the binary search algorithm. We show how binary search works with several examples.

4. Example 1 – Suppose we are looking for 11 in the array below:

BinarySearch ( vals=0 1 2 3 4 5 6 7 8 9 10 11 122 4 7 10 11 45 50 59 60 66 69 70 79 , key=11 )

a. Find index of the middle of the list, (12-0)/2=6. Then, since key<vals[6], call BinarySearch on the left half of the list:

BinarySearch ( vals=0 1 2 3 4 52 4 7 10 11 45 , key=11 )

b. Find index of the middle of the list, (5-0)/2=2. Then, since key>vals[2] , call BinarySearch on the right half of the current list:

BinarySearch ( vals=3 4 5

10 11 45 , key=11 )c. Find index of the middle of the list, 3+(5-3)/2=4. Then, since key==vals[4], return 4

(It is customary for the binary search algorithm to return the index where the key was found.)

5. Example 2 – Suppose we are looking for 62 in the array below. This example shows what happens when the key is not found and will help us develop a base case

BinarySearch ( vals=0 1 2 3 4 5 6 7 8 9 10 11 122 4 7 10 11 45 50 59 60 66 69 70 79 , key=62 )

a. Let’s introduce variables, low and high to keep track of the beginning and end of the list, respectively:

low

mid

high

0 1 2 3 4 5 6 7 8 9 10 11 122 4 7 10 11 45 50 59 60 66 69 70 79

20

Page 21: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

b. As before, find index of middle value: mid= low+high2

=6. Then, since: key>vals[6], change

low=mid+1=7 and call BinarySearch on the list indexed from low to high.

BinarySearch ( vals=

low

mid

high

7 8 9 10 11 1259 60 66 69 70 79

, key=62 )c. Find index of middle value: mid= low+high

2=9. Then, since key<vals[9] , change high=mid−1=8

BinarySearch ( vals=

low, mid

high

7 859 60

, key=62 )d. Find index of middle value: mid= low+high

2=7. Then, since key>vals[7] , change low=mid+1=8

BinarySearch ( vals=

low, mid, high8

60, key=62 )

e. Find index of middle value: mid= low+high2

=8. Since low, mid, and high are all the same this indicates that

the key is not present. However, when the key is not found, it is customary to return the location where the key would occur if it were inserted into the list. One way to do this is to proceed as we have so far:

Since key>vals[8] , change low=mid+1=9

BinarySearch ( vals=

high

low

8 960 66

, key=62 )f. Now, since low>high, this means that the key falls between vals [8] and vals [9]. Thus, if the key were to be

inserted in the proper order, it would be at index 9 (the 10th element). It is customary for the binary search algorithm to return -10 in this situation (for this example). The negative sign means that the key was not found. This begs the question as to why the method algorithm doesn’t just return -9 since that is the index where it belongs. See the next two examples!

6.a. Example 3a – Suppose we are looking for 2 in the array below.

BinarySearch ( vals=0 1 2 3 4 5 6 7 8 9 10 11 122 4 7 10 11 45 50 59 60 66 69 70 79 , key=2 )

21

Page 22: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

The method returns 0 because that is the index where the key was found, vals[0].

b. Example 3b – Suppose we are looking for 1 in the array (same as previous array) below.

BinarySearch ( vals=0 1 2 3 4 5 6 7 8 9 10 11 122 4 7 10 11 45 50 59 60 66 69 70 79 , key=1 )

Of course binarySearch will not find the key. Now, suppose we’ve coded it so that when it failed to find the key it returned the negative of the index of where it would belong in the list if it were inserted. Then, in the example above, “1” belongs at index 0, so we return -0, which is just 0. Thus, we see that the results would be ambiguous when 0 is returned. Does 0 mean the key was found or does it mean the key belongs in the element at index=0? Thus, the standard version of binarySearch returns the negative of the position in the list, e.g. return –low-1. For the example above, binarySearch returns -1. We say a bit more about this at the end of this section.

7. Let’s summarize with a rough draft of a recursive algorithm to do binary search.

BinarySearch( list, key )1. Find middle item2. If key=middle

Return index of middleElse if key < middle

BinarySearch( leftSubList, key )Else

BinarySearch( rightSubList, key )

8. We have two issues to resolve:

a. How do we tell the algorithm to search on the left (or right) sublist?b. How do we define a stopping rule?

We’ll need to think carefully about this. Let’s assume we have an index based list that is numbered from 0 to length-1.

9. As we saw earlier, let’s indicate the portion of the list that we want to consider with the variables low and high. Then, we can find the index of the middle item with:

mid= low+high2

And thus the middle item is: vals [middle ] and:

leftSubList is the elements from low to high=mid−1 rightSubList is the elements from mid+1 to high

10. Now, how do we know when to stop the recursion? As we said earlier:

if low > high // key not foundreturn –low-1

22

Page 23: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

11. Binary Search implementation for an array of integers.

public static int binarySearch( int[] vals, int key ) {return binarySearch( vals, key, 0, vals.length-1 );

}

private static int binarySearch( int[] vals, int key, int low, int high ) {

if( low > high ) // key not foundreturn -(low+1);

else {int mid = (low+high)/2;

if( key < vals[mid] ) // search left sub-listreturn binarySearch( vals, key, low, mid-1 );

else if( key > vals[mid] ) // search right sub-listreturn binarySearch( vals, key, mid+1, high );

elsereturn mid;

}}

12. Binary search is incredibly fast. Suppose we have n items in a list. It turns out that the maximum number of

iterations is log2n+1. Compare that to brute force search which on average takes n2 iterations. As shown in the

table below, the difference is astounding!

Iterationsn Binary Search – Worst Case Brute Force Search – Average Case

10 5 5100 8 50

1,000 11 500100,000 18 50,000

1,000,000 21 500,0001,000,000,000 31 500,000,000

1,000,000,000,000 41 500,000,000,000

13. We stated above that when binary search returns a negative number this means the item was not found. Specifically, we wrote in the algorithm above that if the item was not found, we return:

return -(low+1);

What does this number mean? We can use it to tell us the index of where the key would belong in the list. For example:

int index = binarySearch( vals, key );

if( index < 0 ) { // key not foundloc = -1*index - 1;System.out.println( "Key belongs at index:" + loc );System.out.println( "Next value greater than key: " + vals[loc] );

}

23

Page 24: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Thus, if the return from binarySearch is negative, then make it positive and subtract 1. This new value tells us where we would insert this value should we want to. It also tells you where the values are that are bigger (or smaller) than the key. In other words, it provides information about where the key belongs in the list. If the modified index is equal to the length of the list, then this means that the key is larger than all items in the list. Consider this example:

list=[1, 4, 8, 10, 17, 33]

Key

index (returned from binary search) loc=-index-1 Next Item Above

-4 -1 -(-1)-1=0 List[0]=13 -2 -(-2)-1=1 List[1]=45 -3 2 List[2]=89 -4 3 List[3]=10

13 -5 4 List[4]=1728 -6 5 List[5]=3399 -7 6 Bigger than all items in list

Section 18.6 – Case Study: Finding the Folder Size

Omit

We will consider a slightly different problem than the one in the text. Here, we consider displaying all the files and folders within a folder, recursively. The text considers finding the total folder size (including subfolders).

1. Problem - Suppose you have a reference to a folder on your hard drive. Display all the files and folders recursively.

Consider folder abc below: We would like the display to look something like this:

abc:folder b:folder

dd.class:file dd.java:file

g:folderee.class:file ee.java:file r:folder

jj.docx:file nn.docx:file

a.doc:file dd2.abc:file dd3.abc:file dd.abc:file

24

Page 25: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

2. Algorithm

Input: a reference to a folder.

Steps:

1. Print folder name2. Obtain the a list of the files and folders inside the input folder. 3. Loop through the list

3a. If item is a file, print the name3b. Else if item is a folder, print the name and go to step 1

Pseudo-code:

PrintFolder( inFolder )Print folder namelist = Get list of files and folders contained in inFolderFor each item in list

If item is a file, print file nameElse if item is a folder, call PrintFolder( item )

3. Implementation

import java.io.*;public class ListFiles{ public static void main(String[] args) { File folder = new File("abc"); printFolder( folder ); }

private static void printFolder( File folder) { System.out.println( folder.getName() + ":folder"); File[] files = folder.listFiles(); for( File f : files ) { if( !f.isDirectory() ) System.out.println( f.getName() + ":file" ); else printFolder( f ); } }}

Output:

abc:foldera.doc:fileb:foldercc.b:filecc2.b:filedd.abc:filedd2.abc:filedd3.abc:fileg:foldera.txt:fileb.txt:filer:folderjj.doc:filenn.doc:file

25

Page 26: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

4. What could we do to make the output indent for folders? We could use a recursive helper method. Every time we recursively call the method, we increment a string that specifies how much indention.

private static void printFolder( File folder ) { printFolderWithIndent( folder, "" ); }

private static void printFolderWithIndent( File f, String indent ) { System.out.println( indent + f.getName() + ":folder" ); indent += " "; File[] files = f.listFiles(); for( File f2 : files ) { if( !f2.isDirectory() ) System.out.println( indent + f2.getName() + ":file" ); else printFolderWithIndent( f2, indent ); } }

Output:abc:folder a.doc:file b:folder cc.b:file cc2.b:file dd.abc:file ...

Section 18.7 – Case Study: Towers of Hanoi

Omit.

Section 18.8 – Case Study: Fractals

Omit.

Section 18.9 – Recursion vs. Iteration

1. Recursion is another form of program control. It is repetition, but without a loop.2. Recursion is more expensive than iteration in terms of time and space. Each recursive call means the

JVM must create space on the stack for the local variables and parameters and put them there. This requires extra time to manage this space. However, tail recursion (see next section) is nearly identical to iteration.

3. Which should you use? Recursion or iteration? Use the one that provides an intuitive solution that mirrors the problem. If an iterative solution is obvious, use it as it will generally be more efficient than the recursive solution.

4. Any problem that can be solved recursively can be solved iteratively.

26

Page 27: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Section 18.10 – Tail Recursion

1. A recursive method is said to be tail recursive if there are no pending operations to be performed on return from a recursive call. Tail recursion is desirable because some compilers can optimize tail recursion to reduce stack space.

2. Example – This method is not tail recursive because when the recursive call, factorial(n-1) returns, the result must be multiplied by n.

public static long factorial( long n ) {if( n == 0 )

return 1;else

return n * factorial(n-1);}

3. Example – This method is tail recursive:

private static boolean isPalindrone( String msg, int low, int high ) {if( low >= high )

return true;if( msg.charAt(low) == msg.charAt(high) )

return isPalindrone( msg, low+1, high-1 );else

return false;}

4. You can often convert a recursive method to a tail-recursive method by using a helper method with an extra parameter. This parameter is used to store the pending operation so that there is no longer a pending operation.

5. Example – Factorial, tail-recursive.

public static long factorial(int n) {return factorial( n, 1 );

}

private static long factorial(int n, long result ) {if (n == 1)

return result;else

return factorial(n - 1, n*result );}

6. Example – Problem 18.4.

Not tail recursive:

public static double sumBack( int n ) {if( n == 1 ) return 1;return 1.0/n + sumBack(n-1);

}

27

Page 28: Valdosta State University · Web viewCS 1302 – Chapter 18. Recursion. These notes cover Sections 18.1-18.5, 18.9-18.10. Section . 18.1 – I. ntroduction. A . recursive method .

Tail recursive:

public static double sumBack2( int n ) {return sumBack2(n,1);

}

private static double sumBack2( int n, double result ) {if( n == 1 ) return result;return sumBack2(n-1, 1.0/n+result);

}

28


Recommended