Advanced Recursion
description
Transcript of Advanced Recursion
Advanced Recursion
Recursive Function Example: Factorial
Problem: calculate n! (n factorial)n! = 1 if n = 0
n! = 1 * 2 * 3 *...* n if n > 0
Recursively:if n = 0, then n! = 1if n > 0, then n! = n * (n-1)!
Solving Recursive Problems
• See recursive solutions as two sections:– Current– Rest
N! = N * (N-1)!7! = 7 * 6! 7! = 7 * (6 * 5 * 4 * 3 * 2 * 1 * 1)
Factorial Function
function Factorial returnsa Num (n isoftype in Num)// Calculates n factorial, n! // Precondition: n is a non-negative// integer if (n = 0) then Factorial returns 1 else Factorial returns n * Factorial(n-1) endifendfunction //Factorial
if (0 = 0) then Fact returns 1 else Fact returns 1 endifendfunction //Fact
if (1 = 0) then Fact returns 1 else Fact returns 1 * Fact(0) endifendfunction //Factif (2 = 0)
then Fact returns 1 else Fact returns 2 * Fact(1) endifendfunction //Fact
if (3 = 0) then Fact returns 1 else Fact returns 3 * Fact(2) endifendfunction //Fact
algorithm Test ans <- Fact(3)endalgorithm
Tracing Details
function Fact returnsa Num (2) if (2 = 0) then Fact returns 1 else Fact returns 2 * Fact(1) endifendfunction //Fact
1. Actual parameters stored on the stack
2. Recursive call to Fact
4. Unfinished Business
3. Create a new Stack Frame
5. Return value and release stack frame
Activation Stack for Factorial
Call the function: answer <- Fact(5)
Main Algorithm: Unfinished: answer <- Fact (5)
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Fact. 3rd: N=3, Unfinished: 3*Fact(2)
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Fact. 3rd: N=3, Unfinished: 3*Fact(2)
Fact. 4th: N=2, Unfinished: 2*Fact(1)
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Fact. 3rd: N=3, Unfinished: 3*Fact(2)
Fact. 4th: N=2, Unfinished: 2*Fact(1)
Fact. 5th: N=1, Unfinished: 1*Fact(0)
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Fact. 3rd: N=3, Unfinished: 3*Fact(2)
Fact. 4th: N=2, Unfinished: 2*Fact(1)
Fact. 5th: N=1, Unfinished: 1*Fact(0)
Fact. 6th: N=0, Finished: returns 1
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Fact. 3rd: N=3, Unfinished: 3*Fact(2)
Fact. 4th: N=2, Unfinished: 2*Fact(1)
Fact. 5th: N=1, Finished: returns 1*1
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Fact. 3rd: N=3, Unfinished: 3*Fact(2)
Fact. 4th: N=2, Finished: returns 2*1
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Unfinished: 4*Fact(3)
Fact. 3rd: N=3, Finished: returns 3*2
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Unfinished: 5*Fact(4)
Fact. 2nd: N=4, Finished: returns 4*6
Activation Stack for Factorial
Main Algorithm: Unfinished: answer <- Fact (5)
Fact. 1st: N=5, Finished: returns 5*24
Activation Stack for Factorial
Main Algorithm: Finished: answer <- 120
Exponentiation
baseexponent
e.g. 53
Could be written as a function
Power(base, exp)
LB
Can we write it recursively?
be = b * b(e-1)
What’s the limiting case?
When e = 0 we have b0 which always equals?
1
LB
Another Recursive Function
function Power returnsa Num (base, exp isoftype in Num)// Computes the value of BaseExp // Pre: exp is a non-negative integer if (exp = 0) then Power returns 1 else Power returns base * Power(base, exp-1) endifendfunction //Power
Function Power returnsa Num (base, exp isoftype in Num)//Computes the value of BaseExp
//Preconditions: exp is a non-negative integer if(exp = 0 ) then Power returns 1 else Power returns (base * Power(base, exp – 1)) endifendfunction //Power
Activations Stack Example
Algo: total <- Power(3,4)
Power base = 3 exp = 4 3 *Power(3,3)
Power base = 3 exp = 3 3 *Power(3,2)
Power base = 3 exp = 2 3 *Power(3,1)
Power base = 3 exp = 1 3 *Power(3,0)
Power base = 3 exp = 0 Finished: 1
Total <- 81
1
3
9
27
1
3
9
27
81
Bunnies?
• The Time: 13th Century• The Place: Italy• The Man: Fibonacci• The Problem: We start with a pair of newborn rabbits.
At the end of the 2nd month, and each month thereafter the female gives birth to a new pair of rabbits: one male and one female. The babies mature at the same rate as the parents and begin to produce offspring on the same schedule. So how many rabbits do we have at the end of one year?
LB
= 1 pair bunnies (m/f)LB
Fibonacci Number Sequence
if n = 1, then Fib(n) = 1if n = 2, then Fib(n) = 1if n > 2, then Fib(n) = Fib(n-2) + Fib(n-1)
Numbers in the series:1, 1, 2, 3, 5, 8, 13, 21, 34, ...
A More Complex Recursive Function
Fibonacci Sequence Function
function Fib returnsa Num (n iot in Num)// Calculates the nth Fibonacci number // Precondition: N is a positive integer if ((n = 1) OR (n = 2)) then Fib returns 1 else Fib returns Fib(n-2) + Fib(n-1) endifendfunction //Fibonacci
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns Fib(3) + Fib(4)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns Fib(3) + Fib(4)
Fib(3): Fib returns Fib(1) + Fib(2)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns Fib(3) + Fib(4)
Fib(3): Fib returns Fib(1) + Fib(2)
Fib(1): Fib returns 1
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns Fib(3) + Fib(4)
Fib(3): Fib returns 1 + Fib(2)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns Fib(3) + Fib(4)
Fib(3): Fib returns 1 + Fib(2)
Fib(2): Fib returns 1
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns Fib(3) + Fib(4)
Fib(3): Fib returns 1 + 1
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns Fib(2) + Fib(3)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns Fib(2) + Fib(3)
Fib(2): Fib returns 1
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + Fib(3)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + Fib(3)
Fib(3): Fib returns Fib(1) + Fib(2)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + Fib(3)
Fib(3): Fib returns Fib(1) + Fib(2)
Fib(1): Fib returns 1
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + Fib(3)
Fib(3): Fib returns 1 + Fib(2)
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + Fib(3)
Fib(3): Fib returns 1 + Fib(2)
Fib(2): Fib returns 1
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + Fib(3)
Fib(3): Fib returns 1 + 1
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + Fib(4)
Fib(4): Fib returns 1 + 2
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- Fib(5)
Fib(5): Fib returns 2 + 3
Tracing with Multiple Recursive Calls
Main Algorithm: answer <- 5
Mutual Recursion
Recursion doesn’t always occur because a routine calls itself...
Mutual Recursion occurs when two routines call each other.
A BB A
Mutual Recursion Example
Problem: Determine whether a number, N, is odd or even.
• If N is equal to 0, then n is even• N is odd if N-1 is even
Example Implementationfunction Odd returnsa Boolean (n iot in Num) if (n = 0) then Odd returns FALSE else Odd returns Even (n - 1) endifendfunction //Odd
function Even returnsa Boolean (n iot in Num) if (n = 0) then Even returns TRUE else Even returns Odd (n - 1) endifendfunction //Even
Building Recursive Modules• Decide on the terminating condition• Decide the final actions when you terminate
– There may be none– If you are computing something, this usually
starts a “ripple” of returned data• Decide how to take a step closer to terminating
– think about how to make your original, complex problem simpler
• Decide how to call a “clone” of this module• Decide what work to do at this step in recursion
Binary Search: Telephone Book
• Problem: Search the telephone book for someone’s phone number.
• Binary Search Strategy:a. Open the book somewhere near the middle.b. If the the person’s name is in the first half, ignore the
second half, and search the first half, starting again at step a).
c. If the the person’s name is in the second half, ignore the first half, and search the second half, starting again at step a).
d. If the person’s name is on a given page, scan the page for the person’s name, and find the phone number associated with it.
Binary Search: Search an Array• Problem: Given an array, A[ ], of n integers, sorted
from smallest to largest, determine whether value v is in the array.
• Binary Search Strategy:If n = 1 then check whether A[0] = v. Done.
Otherwise, find the midpoint of A[ ]. If v > A[midpoint] then recursively search the second
half of A[ ].If v <= A[midpoint] then recursively search the first half of A[ ].
Search an Array: Implementation
int binarySearch( int A[ ], int v, int first, int last ){ if( first > last ) return -1; // v not found in A[ ]
int mid = (first + last)/2; // set mid to midpoint
if(v == A[mid]) return mid; if(v < A[mid]) return binarySearch(A, v, first, mid-1 ); return binarySearch( A, v, mid+1, last );}
Implementation (2)
Two common mistakes:
1) CORRECT: mid = ( first + last )/2; INCORRECT: mid = ( A[first] + A[last] )/2;
2) CORRECT: return binarySearch( A, v, mid+1, last ); INCORRECT: return binarySearch( A, v, mid, last );
Search an Array: Implementation Notes
• The whole array, A[ ], is passed with each call to binarySearch( ).
• The active part of array A[ ] is defined by first and last.
• A return value of -1 means that v was not found.
Search an Array: Example• Suppose int A[ ] contains {1, 5, 9, 13, 17, 19, 23}, and
we are interested in searching for 19.• Executing binarySearch( A, 19, 0, 6 );
results in 0 1 2 3 4 5 6A 1 5 9 13 17 19 23
first lastmid
first mid last(found at mid!)
Search an Array: Example (Cont’d.)• Suppose we are interested in searching for 21:
1 5 9 13 17 19 23
first lastmid
first mid last
first, mid, last
last first(last before first!)
Search an Array: Final Comments
• Suppose that we have an array of a million numbers.• The first decision of a binary search will eliminate
approximately half of them, or 500,000 numbers.• The second decision will eliminate another 250,000.• Only 20 decisions are needed to determine whether a
given number is among a sorted list of 1 million numbers!
• A sequential search might have to examine all of them.
• Additional Note: Binary searching through a billion numbers would require about 30 decisions, and a trillion numbers would (theoretically) require only 40 decisions.
Famous Problem
• Greatest Common Divisor• Factorial
Questions?