Download chapter 1

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
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
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
o make a smaller triangle and ask it for its area
Triangle 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();
smallerArea + width;
}
return
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 solution
of 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
o The string we are permuting (word)
o Position of the current character (current)
o PermutationGenerator of the substring (tailGenerator)
asks tailGenerator for its next
permutation and returns
• nextPermutation
word.charAt(current) + tailGenerator.nextPermutation();
Handling the Special Case
• When the tail generator runs out of
permutations, we need to:
o Increment the current position
o Compute the tail string that contains all
letters
except for the current one
o 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:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
/**
Computes the next permutation of the word.
@return the next permutation
*/
public String nextPermutation()
{
if (word.length() == 1)
{
current++;
return word;
}
String r = word.charAt(current) + tailGenerator.nextPermutation();
if (!tailGenerator.hasMorePermutations())
{
current++;
if (current < word.length())
{
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 isPalindrone
calls 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)))
Syntax Diagram for Evaluating
and Expression
Syntax Tree for Two Expressions
Mutually Recursive Methods
• Implement 3 methods that call each
other recursively
o getExpressionValue
o getTermValue
o 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:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
@return the value of the expression.
*/
public int getExpressionValue()
{
int value = getTermValue();
boolean done = false;
while (!done)
{
String next = tokenizer.peekToken();
if ("+".equals(next) || "-".equals(next))
{
tokenizer.nextToken();
int value2 = getTermValue();
if ("+".equals(next)) value = value + value2;
else value = value - value2;
}
else done = true;
}
return value;
}
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
/**
Evaluates the next term found in the expression.
@return the value of the term.
*/
public int getTermValue()
{
int value = getFactorValue();
boolean done = false;
while (!done)
{
String next = tokenizer.peekToken();
if ("*".equals(next) || "/".equals(next))
{
tokenizer.nextToken();
int value2 = getFactorValue();
if ("*".equals(next)) value = value * value2;
else value = value / value2;
}
else done = true;
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
}
return value;
}
/**
Evaluates the next factor found in the expression.
@return the value of the factor.
*/
public int getFactorValue()
{
int value;
String next = tokenizer.peekToken();
if ("(".equals(next))
{
tokenizer.nextToken();
value = getExpressionValue();
next = tokenizer.nextToken(); // read ")"
}
else
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:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
/**
Peeks at the next token without consuming it.
@return the next token or null if there are no more tokens
*/
public String peekToken()
{
if (start >= input.length()) return null;
else return input.substring(start, end);
}
/**
Gets the next token and moves the tokenizer to the
following token.
@return the next token or null if there are no more tokens
*/
public String nextToken()
{
String r = peekToken();
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 by
f1 = 1
f2 = 1
fn = 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
o Both are conceptually easy to
understand and program
o Iterative solution is much faster
The Efficiency of Recursion
• Palindrome test can be
implemented as either recursion
or iteration
o Both are easy to program
o Both run about the same speed
The Efficiency of Recursion
• Permutation generator can be
solved using either recursion or
iteration
o Recursive solution is
dramatically easier to understand
and implement
o 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: }
Call Pattern of the Recursive
fib Method
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:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
System.exit(0);
}
/**
Computes a Fibonacci number.
@param n an integer
@return the nth Fibonacci number
*/
public static double fib(int n)
{
if (n <= 2) return 1;
double fold = 1;
double fold2 = 1;
double fnew = 1;
for (int i = 3; i <= n; i++)
{
fnew = fold + fold2;
fold2 = fold;
fold = fnew;
38:
}
39:
return fnew;
40: }
41: }