500 likes | 586 Views
CHAPTER 17. RECURSION. 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
E N D
CHAPTER 17 RECURSION
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
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
The Third Triangle Number • 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 of Width 1 • The triangle consists of a single square • Its area is 1 • Add the code to getArea method for width 1 public int getArea() { if (width == 1) return 1; }
Handling 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 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 • 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
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 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: }
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: }
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 will list all permutations of a string • A permutation is a rearrangement of the letters • The string "eat" has six permutations "eat" "eta" "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
To Generate All Permutations • 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: /** 02: This class generates permutations of a word. 03: */ 04: class PermutationGenerator 05: { 06: /** 07: 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: }
18: 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: { 27: current++; 28: return word; 29: } 30: 31: String r = word.charAt(current) + tailGenerator.nextPermutation(); 32: 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: } 43: 44: return r; 45: } 46: 47: /** 48: Tests whether there are more permutations. 49: @return true if more permutations are available 50: */ 51: public boolean hasMorePermutations() 52: { 53: return current < word.length(); 54: } 55: 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); }
Using Mutual Recursion • Problem: to compute the value of arithmetic expressions such as 3 + 4 * 5 (3 + 4) * 5 1 - (2 - (3 - (4 - 5)))
Mutually Recursive Methods • Implement 3 methods that call each other recursively • getExpressionValue • getTermValue • getFactorValue
File Evaluator.java 01: /** 02: A class that can compute the value of an arithmetic expression. 03: */ 04: public class Evaluator 05: { 06: /** 07: Constructs an evaluator. 08: @param anExpression a string containing the expression 09: to be evaluated. 10: */ 11: public Evaluator(String anExpression) 12: { 13: tokenizer = new ExpressionTokenizer(anExpression); 14: } 15: 16: /** 17: Evaluates the expression.
18: @return the value of the expression. 19: */ 20: public int getExpressionValue() 21: { 22: int value = getTermValue(); 23: boolean done = false; 24: while (!done) 25: { 26: String next = tokenizer.peekToken(); 27: if ("+".equals(next) || "-".equals(next)) 28: { 29: tokenizer.nextToken(); 30: int value2 = getTermValue(); 31: if ("+".equals(next)) value = value + value2; 32: else value = value - value2; 33: } 34: else done = true; 35: } 36: return value; 37: }
38: 39: /** 40: Evaluates the next term found in the expression. 41: @return the value of the term. 42: */ 43: public int getTermValue() 44: { 45: int value = getFactorValue(); 46: boolean done = false; 47: while (!done) 48: { 49: String next = tokenizer.peekToken(); 50: if ("*".equals(next) || "/".equals(next)) 51: { 52: tokenizer.nextToken(); 53: int value2 = getFactorValue(); 54: if ("*".equals(next)) value = value * value2; 55: else value = value / value2; 56: } 57: else done = true;
58: } 59: return value; 60: } 61: 62: /** 63: Evaluates the next factor found in the expression. 64: @return the value of the factor. 65: */ 66: public int getFactorValue() 67: { 68: int value; 69: String next = tokenizer.peekToken(); 70: if ("(".equals(next)) 71: { 72: tokenizer.nextToken(); 73: value = getExpressionValue(); 74: next = tokenizer.nextToken(); // read ")" 75: } 76: else 77: value = Integer.parseInt(tokenizer.nextToken());
78: return value; 79: } 80: 81: private ExpressionTokenizer tokenizer; 82: }
File ExpressionTokenizer.java 01: /** 02: This class breaks up a string describing an expression 03: into tokens: numbers, parentheses, and operators 04: */ 05: public class ExpressionTokenizer 06: { 07: /** 08: Constructs a tokenizer. 09: @param anInput the string to tokenize 10: */ 11: public ExpressionTokenizer(String anInput) 12: { 13: input = anInput; 14: start = 0; 15: end = 0; 16: nextToken(); 17: }
18: 19: /** 20: Peeks at the next token without consuming it. 21: @return the next token or null if there are no more tokens 22: */ 23: public String peekToken() 24: { 25: if (start >= input.length()) return null; 26: else return input.substring(start, end); 27: } 28: 29: /** 30: Gets the next token and moves the tokenizer to the 31: following token. 32: @return the next token or null if there are no more tokens 33: */ 34: public String nextToken() 35: { 36: String r = peekToken(); 37: start = end;
38: if (start >= input.length()) return r; 39: if (Character.isDigit(input.charAt(start))) 40: { 41: end = start + 1; 42: while (end < input.length() && Character.isDigit(input.charAt(end))) 43: end++; 44: } 45: else 46: end = start + 1; 47: return r; 48: } 49: 50: private String input; 51: private int start; 52: private int end; 53: }
File EvaluatorTest.java 01: import javax.swing.JOptionPane; 02: 03: /** 04: This program tests the expression evaluator. 05: */ 06: public class EvaluatorTest 07: { 08: public static void main(String[] args) 09: { 10: String input = JOptionPane.showInputDialog("Enter an expression:"); 11: Evaluator e = new Evaluator(input); 12: int value = e.getExpressionValue(); 13: System.out.println(input + "=" + value); 14: System.exit(0); 15: } 16: }
Fibonacci Sequence • Fibonacci sequence is a sequence of numbers defined byf1 = 1f2 = 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
The Efficiency of Recursion • Palindrome test can be implemented as either recursion or iteration • Both are easy to program • Both run about the same speed
The Efficiency of Recursion • 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 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);
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: }
File FibTrace.java 01: import javax.swing.JOptionPane; 02: 03: /** 04: 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); 13: 14: int f = fib(n); 15: 16: System.out.println("fib(" + n + ") = " + f); 17: System.exit(0);
18: } 19: 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: }
File FibLoop.java 01: import javax.swing.JOptionPane; 02: 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: }
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: }