©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15...

37
©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms

Transcript of ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15...

Page 1: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Chapter 15

Recursive Algorithms

Page 2: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Chapter 15 Objectives

After you have read and studied this chapter, you should be able to• Write recursive algorithms for

mathematical functions and nonnumerical operations.

• Decide when to use recursion and when not to.

• Describe the recursive quicksort algorithm and explain how its performance is better than that of selection and bubble sort algorithms.

Page 3: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.1 Basic Elements of Recursion

A recursive method is a method that contains a statement that makes a call to itself.

Any recursive method will include the following three basic elements:• A test to stop or continue the

recursion.• An end case that terminates the

recursion.• A recursive call that continues the

recursion.

Page 4: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.1 Basic Elements of Recursion

These three elements are included in the following recursive factorial method:

public int factorial(int N)

{

if (N == 1){

return 1;

}

else {

return N* factorial(N-1);

}

}

Page 5: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.2 Directory Listing

Recursive algorithms may be used for nonnumerical applications.

This example of a recursive algorithm will list the file names of all files in a given directory of a hard disk and its subdirectories.

Page 6: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.2 Directory Listing

We create a new File object by passing the name of a file or a directory:

File file = new File(“D:/Java/Projects”);

To get an array of names of files and subdirectories, we use the list method.

String[] fileList = file.list();

Page 7: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.2 Directory Listing

Following is the complete directoryListing method (the argument of which is a File object that represents a directory):

Page 8: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.2 Directory Listingpublic void directoryListing(File dir){

String[] fileList = dir.list();

//get the contents

String dirPath = dir.getAbsolutePath();

for (int i=0; i<fileList.length; i++){

File file = new File(dirPath + “/” + fileList[i]);

if(file.isFile()) { //it’s a file

System.out.println(file.getName() );

}else{

directoryListing(file);

//it’s a directory so recurse

}

}

}

Page 9: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.3 Anagram

We can use a recursive method to derive all anagrams of a given word.

When we find the end case (an anagram), we will print it out.

Page 10: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.1

How to generate all the anagrams of a word by using recursion.

Page 11: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.3 Anagram

We find the anagrams by rotating the positions of the letters.

The trick is, when the method is called recursively, we pass a word with the first letter cut off. So the words being passed to successive calls are getting shorter and shorter.

However, we must access all letters of the word in order to print it out.

Page 12: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.3 Anagram

We solve this problem by passing two parameters: the prefix and the suffix of a word.

In each successive call, the prefix increases by one letter and the suffix decreases by one letter.

When the suffix becomes one letter only, the recursion stops.

Page 13: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.3 Anagram

public void anagram(String prefix,

String suffix)

{

String newPrefix, newSuffix;

int numOfChars = suffix.length();

if (numOfChars == 1){

//End case: print out one anagram

System.out.println(prefix + suffix);

}else{

Page 14: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.3 Anagram for (int i = 1; i <= numOfChars; i++){

newSuffix = suffix.substring(1, numOfChars);

newPrefix = prefix + suffix.charAt(0);

anagram(newPrefix, newSuffix);//recursive call

//rotate left to create a //rearranged suffix

suffix = newSuffix + suffix.charAt(0); }}

}

Page 15: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.4 Towers of Hanoi

The goal of the Towers of Hanoi puzzle is to move N disks from peg 1 to peg 3:

• You must move one disk at a time.• You must never place a larger disk on

top of a smaller disk.

Page 16: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.2

Towers of Hanoi with N=4 disks.

Page 17: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.4 Towers of Hanoi

This puzzle can be solved effectively using recursion.

The top N-1 disks must be moved to peg 2, allowing you to then move the largest disk from peg 1 to peg 3.

You can then move the N-1 disks from peg 2 to peg 3.

Page 18: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.3

Recursive solution to the Towers of Hanoi puzzle.

Page 19: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.4 Towers of Hanoipublic void towersOfHanoi (int N,

int from, int to, int spare){if (N == 1){

moveOne(from, to);}else{

towersOfHanoi(N-1, from, spare, to);moveOne (from, to);towersOfHanoi(N-1, spare, to, from);

}}

private void moveOne(int from, int to){System.out.println(from + “--” + to);

}

Page 20: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

The quicksort sorting algorithm uses recursion.

To sort an array from index low to high, we first select a pivot element p.

Any element may be used for the pivot, but for this example we will user number[low].

Page 21: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.4

The core idea of the quicksort algorithm.

Page 22: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

Using p as the pivot, we scan through the array. We move all elements smaller than p to the lower half and all elements larger than p to the upper half.

Then we sort the lower and upper halves recursively, using quicksort.

The variable mid points to the position where the pivot is placed.

Page 23: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

Here is the quicksort algorithm:public void quickSort(int[] number,

int low, int high){

if (low < high){ int mid = partition(number, low, high);

quickSort(number, low, mid-1); quickSort(number, mid+1, high);}

}

The partition method splits the array elements number[low] to number[high] into two halves.

Page 24: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.5

Result of partitioning using 23 as a pivot.

Page 25: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

We first set the pivot to number[low].

We then look for a number smaller than the pivot from position high, high-1, and so on.

The number is found at position J. We move this number to position low.

Page 26: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

Now we look for a number larger than the pivot from low+1, low+2, etc.

The number is found at position I. We move it to position J.

We repeat the process, looking for a number smaller than the pivot from J-1, J-2, and so on.

Page 27: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.6

Details of one partitioning.

Page 28: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

Here is the partition method:private int partition(int[] number,

int start, int end){

//set the pivot

int pivot = number[start];

do{

//look for a number smaller than pivot

//from the end

while(start < end && number[end] >= pivot){

end--;

}

if(start < end){ //found a smaller number

number[start] = number[end];

Page 29: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

//now find a number larger than pivot //from the start while(start < end && number[start] <= pivot){

start++; } if(start < end){ //found a larger number

number[end] = number[start]; }}

} while (start < end);

//done, move the pivot back to the arraynumber[start] = pivot;

return start;}

Page 30: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

In the worst case, quicksort executes roughly the same number of comparisons as the selection sort and bubble sort.

On average, we can expect a partition process to split the array into two roughly equal subarrays.

Page 31: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.7

A hierarchy of partitioning an array into smaller and smaller arrays in the quicksort.

Page 32: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.5 Quicksort

When the size of all subarrays becomes 1, the array is sorted.

The total number of comparisons for sorting the whole array is

K * NN = 2K

log2N = K

KN = N log2N

Page 33: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.6 When Not to Use Recursion

Recursion does not always provide an efficient or natural way to express the solution to a problem.

public int fibonacci(int N){

if (N == 0 )|| N ==1){

return 1; //end case

}else{ //recursive case

return fibonacci(N-1) + fibonacci(N-2);

}

}

Page 34: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

Fig. 15.8

Recursive calls to compute fibonacci(5).

Page 35: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.6 When Not to Use Recursion

This method is succinct and easy to understand, but it is very inefficient. A nonrecursive version is just as easy to understand.

public int fibonacci(int N){

int fibN, fibN1, fibN2, cnt;

if (N == 0 || N == 1){

return 1;

}else{

fibN1 = fibN2 = 1;

cnt = 2;

Page 36: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.6 When Not to Use Recursion while (cnt <= N){

fibN = fibN1 + fibN2;

//get the next Fib. no.

fibN1 = fibN2;fibN2 = fibN;

cnt++; } return fibN; }}

Page 37: ©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 15 Recursive Algorithms.

©TheMcGraw-Hill Companies, Inc. Permission required for reproduction or display.

15.6 When Not to Use Recursion

In general, use recursion if• A recursive solution is natural and

easy to understand.• A recursive solution does not result in

excessive duplicate computation.• The equivalent iterative solution is

too complex.