CHAPTER 17 RECURSION
E N D
Presentation Transcript
CHAPTER GOALS • To learn about the method of recursion • To understand the relationship between recursion and iteration • To analysis problems that are much easier to solve by recursion than by iteration • To learn to think recursively • To be able to use recursive helper methods • To understand when the use of recursion affects the efficiency of an algorithm CHAPTER 17RECURSION
Triangle Numbers • Compute the area of a triangle of width n • Assume each [] square has an area of 1 • Also called the nth triangle number • Example --The third triangle number is 6 [] [] [] [] [] [] • Outline of Triangle Class public class Triangle { public Triangle(int aWidth) { width = aWidth; } public int getArea() { ... } private int width; }
Handling Triangle • Base case: Width 1 • The triangle consists of a single square -- area is 1 • Add the code to getArea method for width 1 public int getArea() { if (width == 1) return 1; } • General case: • Assume we know the area of the smaller, colored triangle • Area of larger triangle can be calculated as:smallerArea + width • To get the area of the smaller triangle • make a smaller triangle and ask it for its areaTriangle smallerTriangle = new Triangle(width - 1); int smallerArea = smallerTriangle.getArea(); [] [] [][] [] [][] [] [] []
Completed getArea method • That method makes a smaller triangle of width 2 • It calls getArea on that triangle • That method makes a smaller triangle of width 1 • It calls getArea on that triangle • That method returns 1 • The method returns smallerArea + width = 1 + 2 = 3 • The method returns smallerArea + width = 3 + 3 = 6 • The method returns smallerArea + width = 6 + 4 = 10 • The code public int getArea() { if (width == 1) return 1; Triangle smallerTriangle = new Triangle(width - 1); int smallerArea = smallerTriangle.getArea(); return smallerArea + width; } • Computing the area of a triangle with width 4 • getArea method makes a smaller triangle of width 3 • It calls getArea on that triangle
Recursion • A recursive computation solves a problem by using the solutionof the same problem with simpler input • For recursion to terminate, there must be special cases for the simplest inputs. • To complete our Triangle example, we must handle width <= 0 • Add this line to the getArea method if (width <= 0) return 0;
File Triangle.java 18: 19: /** 20: Computes the area of the triangle. 21: @return the area 22: */ 23: public int getArea() 24: { 25: if (width <= 0) return 0; 26: if (width == 1) return 1; 27: Triangle smallerTriangle = new Triangle(width - 1); 28: int smallerArea = smallerTriangle.getArea(); 29: return smallerArea + width; 30: } 31: 32: private int width; 33: } 01: /** 02: A triangular shape composed of stacked unit squares like this: 03: [] 04: [][] 05: [][][] 06: . . . 07: */ 08: public class Triangle 09: { 10: /** 11: Constructs a triangular shape 12: @param aWidth the width (and height) of the triangle 13: */ 14: public Triangle(int aWidth) 15: { 16: width = aWidth; 17: }
TriangleTest.java 01: import javax.swing.JOptionPane; 02: 03: public class TriangleTest 04: { 05: public static void main(String[] args) 06: { 07: String input = JOptionPane.showInputDialog("Enter width"); 08: int width = Integer.parseInt(input); 09: Triangle t = new Triangle(width); 10: int area = t.getArea(); 11: System.out.println("Area = " + area); 12: } 13: }
Permutations of a String • Design a class that lists all permutations of a string • A permutation is a rearrangement of the letters • The string "eat" has six permutations:“eat”, “eta”, “aet”, “aet”, “tea”, “tae” • Public Interface of PermutationGenerator class PermutationGenerator { public PermutationGenerator(String s) { . . . } public String nextPermutation() {. . . } public boolean hasMorePermutations() { . . . } }
File PermutationGeneratorTest.java 01: /** 02: This program tests the permutation generator. 03: */ 04: public class PermutationGeneratorTest 05: { 06: public static void main(String[] args) 07: { 08: PermutationGenerator generator 09: = new PermutationGenerator("eat"); 10: while (generator.hasMorePermutations()) 11: System.out.println(generator.nextPermutation()); 12: } 13: }
To Generate All Permutations • Generate all permutations that start with 'e' , then 'a' then 't' • To generate permutations starting with 'e', we need to find all permutations of "at" • This is the same problem with simpler inputs. • Use recursion • nextPermutaion method returns one permutation at a time • PermutationGenerator remembers its state • The string we are permuting (word) • Position of the current character (current) • PermutationGenerator of the substring (tailGenerator) • nextPermutation asks tailGenerator for its next permutation and returnsword.charAt(current) + tailGenerator.nextPermutation();
Handling the Special Case • When the tail generator runs out of permutations, we need to: • Increment the current position • Compute the tail string that contains all letters except for the current one • Make a new permutation generator for the tail string
File PermutationGenerator.java 01: /** This class generates permutations of a word. 03: */ 04: class PermutationGenerator 05: { 06: /** Constructs a permutation generator. 08: @param aWord the word to permute 09: */ 10: public PermutationGenerator(String aWord) 11: { 12: word = aWord; 13: current = 0; 14: if (word.length() > 1) 15: tailGenerator = new PermutationGenerator(word.substring(1)); 16: System.out.println("Generating " + word ); 17: } 19: /** 20: Computes the next permutation of the word. 21: @return the next permutation 22: */ 23: public String nextPermutation() 24: {
25: if (word.length() == 1) 26: { current++; return word; } 31: String r = word.charAt(current) + tailGenerator.nextPermutation(); 33: if (!tailGenerator.hasMorePermutations()) 34: { 35: current++; 36: if (current < word.length()) 37: { 38: String tailString = word.substring(0, current) 39: + word.substring(current + 1); 40: tailGenerator = new PermutationGenerator(tailString); 41: } 42: } 44: return r; 45: } 47: /** Tests whether there are more permutations. 49: @return true if more permutations are available 50: */ 51: public boolean hasMorePermutations() 52: { return current < word.length();} 56: private String word; 57: private int current; 58: private PermutationGenerator tailGenerator; 59: }
Recursive Helper Method • The public boolean method isPalindronecalls helper method isPalindrome(int start, int end) • Helper method skips over matching letter pairs and non-letters and calls itself recursively
Recursive Helper Method public boolean isPalindrome(int start int end) { //separate case for substrings of length 0 or 1 if (start>=end) return true; //get first and last character, converted to lowercase char first = Character.toLowerCase(text.charAt(start)); char last = Character.toLowerCase(text.charAt(end)); if ((Character.isLetter(first) && Character.isLetter(last)) { if (first == last) { //test substring that doesn't contain the matching letters return isPalindrome(start +1, end -1); } else return false; } else if (!Character.isLetter(last)) { //test substring that doesn't contain last character return isPalindrome(start, end -1); } else { //test substring that doesn't contain first character return isPalindrome(start + 1, end); }
Fibonacci Sequence • Fibonacci sequence is a sequence of numbers defined byf1 = 1, f2 = 1fn = fn-1 + fn-2 • First ten terms 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 • The Efficiency of Recursion • You can generate the Fibonacci series using either recursion or iteration • Both are conceptually easy to understand and program • Iterative solution is much faster • Palindrome test can be implemented as either recursion or iteration • Both are easy to program • Both run about the same speed • Permutation generator can be solved using either recursion or iteration • Recursive solution is dramatically easier to understand and implement • Both run at about the same speed
File FibTest.java 18: } 19: System.exit(0); 20: } 21: 22: /** 23: Computes a Fibonacci number. 24: @param n an integer 25: @return the nth Fibonacci number 26: */ 27: public static int fib(int n) 28: { 29: if (n <= 2) return 1; 30: else return fib(n - 1) + fib(n - 2); 31: } 32: } 01: import javax.swing.JOptionPane; 02: 03: /** 04: This program computes Fibonacci numbers using a recursive 05: method. 06: */ 07: public class FibTest 08: { 09: public static void main(String[] args) 10: { 11: String input = JOptionPane.showInputDialog("Enter n: "); 12: int n = Integer.parseInt(input); 13: 14: for (int i = 1; i <= n; i++) 15: { 16: int f = fib(i); 17: System.out.println("fib(" + i + ") = " + f);
File FibTrace.java 20: /** 21: Computes a Fibonacci number. 22: @param n an integer 23: @return the nth Fibonacci number 24: */ 25: public static int fib(int n) 26: { 27: System.out.println("Entering fib: n = " + n); 28: int f; 29: if (n <= 2) f = 1; 30: else f = fib(n - 1) + fib(n - 2); 31: System.out.println("Exiting fib: n = " + n 32: + " return value = " + f); 33: return f; 34: } 35: } 01: import javax.swing.JOptionPane; 03: /** This program prints trace messages that show how often the 05: recursive method for computing Fibonacci numbers calls itself. 06: */ 07: public class FibTrace 08: { 09: public static void main(String[] args) 10: { 11: String input = JOptionPane.showInputDialog("Enter n: "); 12: int n = Integer.parseInt(input); 14: int f = fib(n); 16: System.out.println("fib(" + n + ") = " + f); 17: System.exit(0); 18: }
19: System.exit(0); 20: } 21: 22: /** 23: Computes a Fibonacci number. 24: @param n an integer 25: @return the nth Fibonacci number 26: */ 27: public static double fib(int n) 28: { 29: if (n <= 2) return 1; 30: double fold = 1; 31: double fold2 = 1; 32: double fnew = 1; 33: for (int i = 3; i <= n; i++) 34: { 35: fnew = fold + fold2; 36: fold2 = fold; 37: fold = fnew; 38: } 39: return fnew; 40: } 41: } File FibLoop.java 01: import javax.swing.JOptionPane; 03: /** 04: This program computes Fibonacci numbers using an iterative 05: method. 06: */ 07: public class FibLoop 08: { 09: public static void main(String[] args) 10: { 11: String input = JOptionPane.showInputDialog("Enter n: "); 12: int n = Integer.parseInt(input); 13: 14: for (int i = 1; i <= n; i++) 15: { 16: double f = fib(i); 17: System.out.println("fib(" + i + ") = " + f); 18: }