Introduction to Computer Science Recursion The Runtime Stack Unit 15.

Post on 20-Dec-2015

232 views 3 download

transcript

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);

}}