View
239
Download
3
Embed Size (px)
Citation preview
Introduction to Computer Science
• Recursion
• The Runtime Stack
Unit 15Unit 15
15- 2
Recursion
• A method that calls itself is said to be recursive
• (Another formulation: A message that causes itself to be sent as another message)
• We have been looking a lot at loops: for, while, and do-while loops; recursion can be used as a substitute for loops, but it can do much more
• The ability to use recursion gives Java a lot of power, and gives us a new way of thinking about problem solutions
15- 3
Loop Example:Count Digits in "number"
numberOfDigits = 0;rest = number;do {
// The number of digits in number is// numberOfDigits plus the remaining// digits in restrest = rest / 10;numberOfDigits++;
} while (rest != 0);
15- 4
Recursion Example:Count Digits in "number"
Definition of digits(n):
1 if -9 n 9,digits(n) =
1 + digits(n/10) otherwise.
{
15- 5
Recursion Example:Count Digits in "number"
1 if -9 n 9,digits(n) =
1 + digits(n/10)otherwise.
{digits(321) = 1 + digits(321/10)
= 1 + digits(32)= 1 + (1 +
digits(32/10))= 1 + (1 + digits(3))= 1 + (1 + (1))= 3
15- 6
Recursive Definition
• A definition that is self-referential
• A definition that is defined in terms of simpler instances of itself
• It is not a "circular definition"; that would lead nowhere
• It is a "spiraling definition" that eventually terminates, and that must include a "base case", a final part of the definition that does not call itself
15- 7
Recursion Example:Count Digits in "number"
int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) )
return 1;else
return (1 + numberOfDigits(n/10));}
15- 8
How to Write a Recursive Function, f(x)
• If you want to compute f(x), but can't do it directly–Assume you can compute f(y), for all
values y smaller than x
–Define f(x) in terms of f(y)
–Define the base case(s) — define f(x) directly (i.e., not in terms of f(y)) for some base value(s) of x
15- 9
Counting Digits Recursively, Again
int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) )
return 1;else
return (1 + numberOfDigits(n/10));}
f(x)
15- 10
Counting Digits Recursively, Again
int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) )
return 1;else
return (1 + numberOfDigits(n/10));}
1. We assume we can compute f(y) for y smaller
than x
f(x)
15- 11
Counting Digits Recursively, Again
int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) )
return 1;else
return (1 + numberOfDigits(n/10));}
2. f(x) defined in terms of f(y), where y is smaller
than x
1. We assume we can compute f(y) for y smaller
than x
f(x)
15- 12
Counting Digits Recursively, Again
int numberOfDigits(int n) {if ( (-10 < n) && (n < 10) )
return 1;else
return (1 + numberOfDigits(n/10));}
2. f(x) defined in terms of f(y), where y is smaller
than x
1. We assume we can compute f(y) for y smaller
than x
f(x)
3. Define the base case for some x not in terms
of f(y)
15- 13
Another Example: factorial
int factorial(int n) {// Recursively multiply positive numbers// 1 through n
if ( (n == 0) || (n == 1) )return 1;
elsereturn ( n * factorial(n - 1) );
}
15- 14
Another Example: factorial
int factorial(int n) {// Recursively multiply positive numbers// 1 through n
if ( (n == 0) || (n == 1) )return 1;
elsereturn ( n * factorial(n - 1) );
}
f(x)
15- 15
Another Example: factorial
int factorial(int n) {// Recursively multiply positive numbers// 1 through n
if ( (n == 0) || (n == 1) )return 1;
elsereturn ( n * factorial(n - 1) );
}
1. We assume we can compute f(y) for y smaller
than x
f(x)
15- 16
Another Example: factorial
int factorial(int n) {// Recursively multiply positive numbers// 1 through n
if ( (n == 0) || (n == 1) )return 1;
elsereturn ( n * factorial(n - 1) );
}2. f(x) defined in terms of
f(y), where y is smaller than x
1. We assume we can compute f(y) for y smaller
than x
f(x)
15- 17
Another Example: factorial
int factorial(int n) {// Recursively multiply positive numbers// 1 through n
if ( (n == 0) || (n == 1) )return 1;
elsereturn ( n * factorial(n - 1) );
}2. f(x) defined in terms of
f(y), where y is smaller than x
1. We assume we can compute f(y) for y smaller
than x
f(x) 3. Define the base case for some x not in terms
of f(y)
15- 18
So What's Wrong with This?Recursive Definition of power( )
int power(int k, // number to be raised int n) { // power to which to raise
return ( k * power(k, n-1) );}
Compute kn
Right — missing the base case definition;this will go around in circles
15- 19
Recursive Definition of power( )
int power(int k, // number to be raised
int n) { // power to which to raise
if (n == 0)
return 1;
else
return ( k * power(k, n-1) );
}
15- 20
Recursive Definition of power( )
int power(int k, // number to be raised
int n) { // power to which to raise
if (n == 0)
return 1;
else
return ( k * power(k, n-1) );
}
f(x)
15- 21
Recursive Definition of power( )
int power(int k, // number to be raised
int n) { // power to which to raise
if (n == 0)
return 1;
else
return ( k * power(k, n-1) );
}
f(x)
1. We assume we can compute f(y) for y smaller
than x
15- 22
Recursive Definition of power( )
int power(int k, // number to be raised
int n) { // power to which to raise
if (n == 0)
return 1;
else
return ( k * power(k, n-1) );
}
f(x)
1. We assume we can compute f(y) for y smaller
than x
2. f(x) defined in terms of f(y), where y is smaller
than x
15- 23
Recursive Definition of power( )
int power(int k, // number to be raised
int n) { // power to which to raise
if (n == 0)
return 1;
else
return ( k * power(k, n-1) );
}
f(x)
1. We assume we can compute f(y) for y smaller
than x
2. f(x) defined in terms of f(y), where y is smaller
than x
3. Define the base case for some x not in terms
of f(y)
15- 24
What's the Point?
• We could write power( ) iteratively:
int power(int k, int n) {int result = 1;while (n > 0) {
result = result * k;n--;
}return result;
}
15- 25
Recursion Can Do Better
• Recursion does add overhead to a calculation
• Sometimes it is no better (or even worse) than iteration
• But recursion can also be better:–Recursion can give us a solution where
iteration would be much harder to define
– It can open up superior, more efficient solutions, for us
15- 26
New Definition of power( )
Consider a better, more efficient definition of power( ):
–If n is even, then kn is equal to (k(n/2))2
–If n is odd, then kn is equal tok*(k((n-1)/2))2
This leads to a divide and conquer algorithm; the method makes use of a problem half the size of the original
15- 27
New Definition of power( )
int power(int k, // number to be raised int n) { // power to which to raise
if (n == 0)return 1;
else {int t = power(k, n/2);if ( (n % 2) == 0 )
return (t * t);else
return ( k * t * t );}
}
15- 28
A Few Points on power( )
• t = power(k, n/2) works because integer division gives us n/2 if n is even, and (n-1)/2 if n is odd (just what we wanted)
• The first version of power( ) uses n multiplications to calculate the answer
• This version of power( ) uses log2 n multiplications, a much smaller number
• Again, recursion is not always more efficient• But recursion made the second version
natural
15- 29
Sometimes, the Recursive Call Appears More than Once
• A recursive method can call itself multiple times
• It works the same way:–Assume the recursive calls work
–Define the function in terms of the recursive calls
–Define the base case
15- 30
Another example: Fibonacci
if n is 1 or 2, the nth Fibonacci number is 1
if n is 3 or more, the nth Fibonacci number is the sum of the previous two Fibonacci numbers
Fibonacci sequence:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144…
15- 31
The Recursive fibonacci( ) Definition
int fibonacci (int n) {// Recursively calculates Fibonacci number
if ( (n == 1) || (n == 2) ) return 1;else return ( fibonacci(n – 1) + fibonacci(n – 2) );
}
2. f(x) defined in terms of f(y), where y is smaller
than x
15- 32
Another Example: recursive definition of choose( ) function
• Compute binomial coefficients, "n choose
k", i.e., ( )• Given a set S of n distinct objects, for n ≥1, and a number 0 ≤k ≤n, how many subsets of S have exactly k elements?
• Example: Set S = {1, 2, 3}, k = 2; how many subsets of S have exactly 2 elements? "3 choose 2" is 3 (that is, {1, 2}, {1, 3}, {2, 3} ).
nk
15- 33
Recursion to the Rescue
• The solution would be much more difficult without recursion
• Assume we can calculate the function choose( ) for any values smaller than n and k
• Now define choose( ) in terms of choose( ) over smaller n's and k's…
15- 34
Pick out one element of S; call it a
• Every subset of S either includes a or it doesn't
• We can count the subsets by counting those with a, and counting those without a, and adding them up
• A k-element subset containing a is formed by choosing k - 1 elements from the remaining n - 1
elements of S, so there are ( ) such subsets
• A k-element subset that excludes a is formed by choosing k elements from the remaining n - 1
elements of S, so there are ( ) such subsets
n - 1k - 1
n - 1k
15- 35
Specific Example
• S = {1, 2, 3}, n = 3; k = 2; how many subsets of S have exactly 2 elements? "3 choose 2" is three (that is, {1, 2}, {1, 3}, {2, 3} )
• All these sets either include "1" or they don't
• Notice:
–Two of the sets include "1": {1, 2} and {1, 3}
–One of the sets doesn't include "1": {2, 3}
15- 36
Specific Example, continued
• We can figure out how many sets include "1" by pretending S is {2, 3}, and looking at "n-1 choose k-1" (that is, "2 choose 1"):
• There are two such sets: {2} and {3}
• These correspond to the "n choose k" (that is, "3 choose 2") sets that include "1", namely {1, 2} and {1, 3}
15- 37
Specific Example, continued
• We can figure out how many sets do not include "1" by pretending S is {2, 3}, and looking at "n - 1 choose k" (that is,"2 choose 2"):
• There is one such set: {2, 3}
• This corresponds to the "n choose k" (that is, "3 choose 2") set that doesn't include "1", namely {2, 3}
15- 38
Specific Example, finished
• Add up the number of sets that do include "1" (there are two) with the number of sets that do not include "1" (there is one), and you get the final answer: three
• "3 choose 2" defined in terms of–"2 choose 1" and–"2 choose 2"
• "n choose k" defined in terms of–"n - 1 choose k - 1" and–"n - 1 choose k"
15- 39
So Far, So Good
• But we are not done
• What about the base case(s)?
int choose(int n, int k) { return ( choose(n-1, k-1) + choose(n-1, k) );}
15- 40
The Base Cases
• It turns out that only two base cases are required, when k is 1, and when k is n
• When k is 1, then ( ) is n, because there are n 1-element subsets of an n-element set
• When k is n, then ( ) is 1, because there is 1 n-element subset of an n-element set
nk
nk
15- 41
Recursive Definition of choose( )
int choose(int n, int k) {if (k == 1)
return n;else if (k == n)
return 1;else
return ( choose(n-1, k-1)+ choose(n-1, k) );
}
15- 42
What's Happening in the Computer?
• The runtime stack, which plays an important role when one method sends a message to an object, is important for understanding what's happening with recursion, too
• A brief review…
15- 43
A Stack Handles Nesting
• Let’s improve the way we think about this nesting
• When method e calls method f( ), which calls method g( ), we can think of a “stack of methods”
• Like putting a piece of paper on top of another piece on top of another piece... the topmost piece is the method being executed now, the others we’ll return to
• Each piece of paper holds the parameters and local variables
15- 44
Starting Execution in main( )
Method main( )
STACK
public static void main (String[ ] args) {.........obj.e();...}
top
15- 45
Call to method e( )
Method e( )Where we came from: main, line 4
Method main( )
STACK
void e ( ) {......obj.f( );...}
public static void main (String[ ] args) {.........obj.e();...}
top
15- 46
Executing method e( )
Method e( )Where we came from: main, line 4
Method main( )
STACK
void e ( ) {......obj.f( );...}
public static void main (String[ ] args) {.........obj.e();...}
top
15- 47
Call to method f( )
Method e( )Where we came from: main, line 4
Method main( )
STACK
Method f( )Where we came from: e, line 3
void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);}
void e ( ) {......obj.f( );...}
public static void main (String[ ] args) {.........obj.e();...}
top
15- 48
Executing method f( )
Method e( )Where we came from: main, line 4
Method main( )
STACK
Method f( )Where we came from: e, line 3
void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);}
void e ( ) {......obj.f( );...}
public static void main (String[ ] args) {.........obj.e();...}
top
15- 49
Call to method g( )
Method e( )Where we came from: main, line 4
Method main( )
STACK
Method f( )Where we came from: e, line 3
Method g( )Where we came from: f, line 4
top
void g ( ) { System.out.println(“A!”); System.out.println(“B!”); System.out.println(“C!”); System.out.println(“D!”);}
void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);}
void e ( ) {......obj.f( );...}
main (String[ ] args) {.........obj.e();...}
15- 50
Method g( ) finishes,the stack has its top removed
void g ( ) { System.out.println(“A!”); System.out.println(“B!”); System.out.println(“C!”); System.out.println(“D!”);}
void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);}
void e ( ) {......obj.f( );...}
main (String[ ] args) {.........obj.e();...}
Method e( )Where we came from: main, line 4
Method main( )
STACK
Method f( )Where we came from: e, line 3
top
15- 51
Method f( ) finishes,the stack has its top removed
void g ( ) { System.out.println(“A!”); System.out.println(“B!”); System.out.println(“C!”); System.out.println(“D!”);}
void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);}
void e ( ) {......obj.f( );...}
main (String[ ] args) {.........obj.e();...}
Method e( )Where we came from: main, line 4
Method main( )
STACK
top
15- 52
Method e( ) finishes,the stack has its top removed
void g ( ) { System.out.println(“A!”); System.out.println(“B!”); System.out.println(“C!”); System.out.println(“D!”);}
void f ( ) { System.out.println(“Hi there!”); System.out.println(“Nice weather!”); ... obj.g( ); System.out.println(“That was fun!”); System.out.println(“Time to move on!”);}
void e ( ) {......obj.f( );...}
main (String[ ] args) {.........obj.e();...}
Method main( )
STACK
top
15- 53
Variables are held on the stack, too
• When we put items on the stack, we also write down–values of parameters
– local variables
• Now, let's look at a recursive example, namely power( )
• The runtime stack keeps track of where we came from and where we'll return to
15- 54
Call to power(7, 5) from main( )
public static void main (String[ ] args) {
…
int x = power(7, 5);
…
}
15- 55
A reminder of power( ); parameters k and n; local variable t
int power(int k, // number to be raised int n) { // power to which to raise
if (n == 0)return 1;
else {int t = power(k, n/2);if ( (n % 2) == 0 )
return (t * t);else
return ( k * t * t );}
}
15- 56
Delayed Evaluation
• The recursive call to a method leaves partially evaluated expressions on the stack
• The recursive call typically occurs while an expression is being calculated. The stack delays the expression’s evaluation
• In this case, we'll delay the evaluation oft = power(k, n/2);
15- 57
The Runtime Stack (recursion)
Method power( )Where we came from: main, line …k: 7n: 5t: uninitializedMethod main( )
STACK
top
int power(int k, // number to be raisedint n) { // power to which to raise
if (n == 0)return 1;
else {int t = power(k, n/2);if ( (n % 2) == 0 )
return (t * t);else
return ( k * t * t );}
}
15- 58
The Runtime Stack (recursion)
Method power( )Where we came from: main, line …k: 7n: 5t: uninitializedMethod main( )
STACK
top
Method power( )Where we came from: power, line 6k: 7n: 2t: uninitialized
Method power( )Where we came from: main, line …k: 7n: 5t: uninitializedMethod main( )
STACK
top
Method power( )Where we came from: power, line 6k: 7n: 2t: uninitialized
Method power( )Where we came from: power, line 6k: 7n: 1t: uninitialized
Method power( )Where we came from: main, line …k: 7n: 5t: uninitializedMethod main( )
top
Method power( )Where we came from: power, line 6k: 7n: 2t: uninitialized
Method power( )Where we came from: power, line 6k: 7n: 1t: uninitialized
Method power( )Where we came from: power, line 6k: 7n: 0t: uninitialized
15- 61
n equal to zero causes power( ) to return 1, and sets t to returned value
Method power( )Where we came from: main, line …k: 7n: 5t: uninitializedMethod main( )
Method power( )Where we came from: power, line 6k: 7n: 2t: uninitialized
Method power( )Where we came from: power, line 6k: 7n: 1t: 1
top
15- 62
Returning to power( ), line 7, we return k*t*t (i.e., 7) from line 10
Method power( )Where we came from: main, line …k: 7n: 5t: uninitializedMethod main( )
Method power( )Where we came from: power, line 6k: 7n: 2t: 7
top
STACK
15- 63
The value of n is 2, n%2 is 0, and we return t*t (i.e., 49) from line 8
Method power( )Where we came from: main, line …k: 7n: 5t: 49Method main( )
top
STACK
int power(int k, // number to be raisedint n) { // power to which to raise
if (n == 0)return 1;
else {int t = power(k, n/2);if ( (n % 2) == 0 )
return (t * t);else
return ( k * t * t );}
}
15- 64
Finally, power( ) sees that n is 5, n%2 is 1, and it returns k*t*t to main
Method main( )top
STACK
main( ) gets value
16,807
int power(int k, // number to be raisedint n) { // power to which to raise
if (n == 0)return 1;
else {int t = power(k, n/2);if ( (n % 2) == 0 )
return (t * t);else
return ( k * t * t );}
}
15- 65
What You’ve Seen,Recursively-speaking
• Simple recursive functions, f( )–numberOfDigits(n), uses 1 + f(n/10)
–factorial(n), uses n * f(n - 1)
–power(k, n), uses n * f(k, n - 1)
–Then a better power(k, n), using a divide and conquer approach
–fibonacci(n), using f(n - 1) + f(n - 2)
–choose(n, k), using f(n - 1, k - 1) + f(n - 1, k)
• The runtime stack for power(k, n)
15- 66
Another Example ofDelayed Evaluation
int sum (int n) {// Use recursion for addition of positive numbers.// Recursion is *not* the best way to do this…// It's just an example of delayed evaluation
if (n == 1)return 1;
else return ( n + sum(n - 1) );}
15- 67
Let’s say n is 5
Sum = 5 + Sum (5 – 1) // first Sum = 4 + Sum (4 – 1) // second
Sum = 3 + Sum (3 – 1) // third Sum = 2 + Sum (2 – 1) //fourth
Sum = 1 // fifth Sum = 1 // fifth Sum = 2 + 1 // fourth Sum = 3 + 3 // third
Sum = 4 + 6 // secondSum = 5 + 10 // first
return ( n + sum(n – 1) ) // unless n is 1
15- 68
Leaving Statements to be Executed
• Sometimes, as with power( ), there are statements left to execute in the recursive function, after the call to the next copy of itself is finished
• With power( ), after t got its value, there was still a calculation to be carried out before another value was returned
• Here’s another example…
15- 69
Print a Sentence in Reverse
class Recur { // Uses recursion to read a line and echo it in reverse
void stackTheCharacters( ) {char theCharacter;SimpleInput sinp = new SimpleInput(System.in);theCharacter = sinp.readChar( );
if (!sinp.eoln( ))stackTheCharacters( ); // The recursive call.
System.out.print(theCharacter);} // stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a sentence that is not a palindrome.”);
stackTheCharacters( ); //The first call.System.out.println( );}
} //Recur
How does it work?
• When stackTheCharacters( ) is called, it reads a character value for its local variable theCharacter
• stackTheCharacters( ) is then called again, so…• The final statement of the first call, that is
System.out.print(theCharacter), is still waiting when the second call to stackTheCharacters( ) reads the next character
• Eventually we get back to finish the first call, and print theCharacter
Enter a sentence that is not a palindrome.Was that a Toyota I saw??was I atoyoT a taht saW
theCharacter = sinp.readChar( );if (!sinp.eoln( ))
stackTheCharacters( ); System.out.print(theCharacter);
The Role of the Runtime Stack
TheRuntime
StackWas that a Toyota I saw?
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
Remember where we arein main( )
Was that a Toyota I saw?
System.out.println( )
TheRuntime
Stack
theCharacter is ???
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
About to call stackTheCharacters( )
Was that a Toyota I saw?
System.out.println( )
TheRuntime
Stack
theCharacter is ‘W’
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
Called stackTheCharacters( ) (again)
TheRuntime
StackWas that a Toyota I saw?
Syst...(theCharacter)theCharacter is ‘W’
theCharacter is ???
System.out.println( )
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
TheRuntime
StackWas that a Toyota I saw?
Called stackTheCharacters( ) (again2)
Syst...(theCharacter) theCharacter is ‘W’
theCharacter is ???Syst...(theCharacter) theCharacter is ‘a’
System.out.println( )
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
TheRuntime
StackWas that a Toyota I saw?
Called stackTheCharacters( ) (again3)
Syst...(theCharacter) theCharacter is ‘W’
theCharacter is ???
Syst...(theCharacter) theCharacter is ‘a’
Syst...(theCharacter) theCharacter is ‘s’
System.out.println( )
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
TheRuntime
StackWas that a Toyota I saw?
Called stackTheCharacters( ) (again24)
.
.
.
Syst...(theCharacter) theCharacter is ‘W’
theCharacter is ???
Syst...(theCharacter) theCharacter is ‘a’
Syst...(theCharacter) theCharacter is ‘w’
System.out.println( )
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
TheRuntime
StackWas that a Toyota I saw?
Print ‘?’, then finish executing the 23 interrupted instances of stackTheCharacters( )
.
.
.
Syst...(theCharacter) theCharacter is ‘W’
theCharacter is ‘?’
Syst...(theCharacter) theCharacter is ‘a’
Syst...(theCharacter) theCharacter is ‘w’
System.out.println( )
class Recur {void stackTheCharacters( ) {
char theCharacter;SimpleInput sinp = new
SimpleInput(System.in);theCharacter = sinp.readChar(
);if (!sinp.eoln( ))
stackTheCharacters( );System.out.print(theCharact
er);}// stackTheCharacters
public static void main (String[ ] args) {System.out.println(“Enter a
sentence that is not a palindrome.”);
stackTheCharacters( );System.out.println( );}
}
Completing the (Interrupted) Methods (then System.out.println of the main block)
• theCharacter is ‘?’ and we execute System.out.print(‘?’)
Was that a Toyota I saw?
?
• theCharacter becomes ‘w’ and execute System.out.print(‘w’)?w
• theCharacter becomes ‘a’ and execute System.out.print(‘a’)?wa
• theCharacter becomes ‘W’ and execute System.out.print(‘W’)?was I atoyoT a taht saW
...
TheRuntime
Stack
Class Recur {void stackTheCharacters24( ) {
theCharacter = sinp.readChar( );
System.out.print(theCharacter); }
void stackTheCharacters3( ) {theCharacter =
sinp.readChar( );stackTheCharacters4( );System.out.print(theCharact
er); }void stackTheCharacters2( ) {
theCharacter = sinp.readChar( );
stackTheCharacters3( );System.out.print(theCharact
er); }void stackTheCharacters1( ) {
theCharacter = sinp.readChar( );
stackTheCharacters2( );System.out.print(theCharact
er); }public static void main(String[ ]
args) {System.out.println(“Enter a
sentencethat is not a palindrome.”);
stackTheCharacters1( );System.out.println( ); }
} // Recur
Was that a Toyota I saw?
An “unfolded” way of looking at those 24 calls of stackTheCharacters( )
stackTheCharacters1
main
stackTheCharacters2
stackTheCharacters3
. . . ....
Syst...(theCharacter)theCharacter is ‘W’System.out.println( )
theCharacter is ‘?’
Syst...(theCharacter)theCharacter is ‘a’
Syst...(theCharacter)theCharacter is ‘s’
stackTheCharacters24
The “unfolded” statementsthat are executed
System.out.println("Please enter a sentence.");theCharacter =sinp.readChar( ); //Reading in 'W' theCharacter = sinp.readChar( ); // Reading in 'a' theCharacter = sinp.readChar( ); // Reading in 's' theCharacter = sinp.readChar( ); // Reading in ' ' theCharacter = sinp.readChar( ); // Reading in 't' . . . . . // intermediate calls theCharacter = sinp.readChar( ); // Reading in 'w' theCharacter = sinp.readChar( ); // Reading in '?' System.out.print(theCharacter); // Printing the '?' System.out.print(theCharacter); // Printing the 'w' . . . . . // intermediate calls System.out.print(theCharacter); // Printing the 't' System.out.print(theCharacter); // Printing the ' ' System.out.print(theCharacter); // Printing the 's' System.out.print(theCharacter); // Printing the 'a'System.out.print(theCharacter); //Printing the 'W'System.out.println( ); // Last statement in main
15- 82
Tail Recursion
With tail, or end, recursion, there is nothing left to do after the last call. No unfinished statements have been left on the stack.
(The previous example, stackTheCharacters( ), was not an example of tail recursion because the System.out.print( ) call remained to be executed in each copy after the recursive call finished.)
15- 83
Specify the Recursive Procedure like a Loop
Goal: Print a positive integer in reverse.Stacking Plan: Print the ‘ones’ digit.Bound: There are no more digits to print.Unstacking Plan: —
Later we'll see another example where the Unstacking Plan is not empty.
15- 84
An Example of Tail Recursion
Class unDigit {// Recursively reverses the digits of a positive integervoid reverseDigits(int number) {
System.out.print(number % 10); if ( (number / 10) != 0 )
reverseDigits(number/10);}
public static void main (String[ ] args) {int num;SimpleInput sinp = new SimpleInput(System.in);System.out.print("Please enter positive
integer.");num = sinp.readInt( );reverseDigits(num);System.out.println( );
}}
15- 85
Tail Recursion is easilyre-written as an iterative loop
void iterativeReverse(int theNumber) {
do {
System.out.print(theNumber % 10);
theNumber = theNumber / 10;
} while (theNumber != 0) ;
}
Please enter a positive integer.2640770462
15- 86
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 87
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 88
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 89
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 90
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 91
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 92
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 93
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 94
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 95
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 96
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 97
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 98
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 99
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 100
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 101
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 102
The Towers of Hanoi
Move the entire stack from peg A to peg C, while obeying two rules:
1. Only one disk can be moved at a time.
2. A larger disk can never go on top of a smaller one.
Peg A Peg B Peg C
15- 103
The Recursive Solution
1. Move n – 1 disks from A to B.
2. Move 1 disk from A to C.
3. Move n – 1 disks from B to C.
Peg A Peg B Peg C
15- 104
The Recursive Solution
1. Move n – 1 disks from A to B.
2. Move 1 disk from A to C.
3. Move n – 1 disks from B to C.
Peg A Peg B Peg C
15- 105
The Recursive Solution
1. Move n – 1 disks from A to B.
2. Move 1 disk from A to C.
3. Move n – 1 disks from B to C.
Peg A Peg B Peg C
15- 106
The Recursive Solution
1. Move n – 1 disks from A to B.
2. Move 1 disk from A to C.
3. Move n – 1 disks from B to C.
Peg A Peg B Peg C
15- 107
The Recursive Solution
1. Move n – 1 disks from A to B.
2. Move 1 disk from A to C.
3. Move n – 1 disks from B to C.
Peg A Peg B Peg C
15- 108
The Recursive Solution
1. Move n – 1 disks from A to B.
2. Move 1 disk from A to C.
3. Move n – 1 disks from B to C.
Peg A Peg B Peg C
15- 109
The Recursive Solution
1. Move n – 1 disks from A to B.
2. Move 1 disk from A to C.
3. Move n – 1 disks from B to C.
Peg A Peg B Peg C
15- 110
The Recursive Specification
Goal: Solve the Tower of Hanoi problem for height n.
Stacking plan: Move n – 1 disks from fromPeg to usingPeg.
Bound: There’s just one disk left (it goes from fromPeg to toPeg).
Unstacking plan: Move n – 1 disks from usingPeg to toPeg.
We use the “other” peg as a temporary holder, and that peg’s identity keeps changing — so we’ll use fromPeg, toPeg, and usingPeg instead of A, B, C.
15- 111
The Java Method
void move (int height, fromPeg, toPeg, usingPeg) {// Recursive procedure for determining moves.// Keep this order—from, to, using—in mind when you// read the recursive calls.if ( height == 1 )
System.out.println("Move a disk from " + fromPeg + " to " + toPeg);
else {move(height – 1, fromPeg, usingPeg,
toPeg);System.out.println("Move a disk from " +
fromPeg + " to " + toPeg);move(height – 1, usingPeg, toPeg,
fromPeg);}
}
15- 112
The Java Class
class Hanoi {
void move(int height, fromPeg, toPeg, usingPeg) {…}
public static void main (String[ ] args) { int height; SimpleInput sinp=new SimpleInput(System.in);
System.out.print("How many disks are yougoing to start with? ");
height = sinp.readInt( );move(height, 1, 3, 2);
}}