recursion - southern illinois university...
TRANSCRIPT
Recursion
1
!! Solution given in terms of problem. Huh?
!! Each problem is a smaller instance of itself. !
! Implemented via functions. !
! Very powerful solving technique.
What is Recursion?
!! Base case
– the point where the solution is known or obvious !!
! Recursive Step – Expressing the problem as a smaller instance of itself – How you get to the base case
Base Case and Recursive Step
Binary Search
word: brave
aDictionary: A - Z open aDictionary in the middle
A - M search the left half: A - M
A - G search the left half: A - G
A - D search the left half: A - D
A - B search the left half: A - B
B search the right half: B
Base Case
Recursive step
!search(in aDictionary:Dictionary, in word: string) if (aDictionary is one page in size)
Scan the page for the wordelse { Open aDictionary to a point near the middle Determine which half of aDictionary contains the word if (word is in the first half of aDictionary) search(first half of aDictionary, word) else search(second half of aDictionary, word) }
Binary Search
Base case: Assume we know how to scan a page for a word.
Recursive step: Note how in each instance we are solving a smaller version of the original problem.
1.How can you define the problem in terms of a smaller problem of the same type?
!2.How does each recursive call diminish the size of the
problem?
!3.What instance of the problem can serve as the base
case?
!4.As the problem size diminishes, will you reach the base
case?
Four Questions
factorial(n) = n.(n-1).(n-2)...1 n > 0factorial(0) = 1
!! observe that factorial(n-1) = (n-1).(n-2)...1 !! so factorial(n) = n.factorial(n-1) !! The solution to factorial(n) is now given in terms of factorial(n-1), a
similar problem, but smaller.
Factorial
double Factorial(const int n) { // base case if (n == 0) { return (1); } else { // recursive step return ( n * Factorial(n - 1) ); } }
Code: Factorial
1.Label each recursive step with a label, such as A, B,,,Z
!2.Keep a record of the current value of the
function's arguments. !
3.Keep a record of any local variable within the function.
Factorial Traced
Factorial Traced
factorial(5) : n = 5 return (5 * factorial(4): A
factorial(2) : n = 2 return (2 * 1): A
factorial(3) : n = 3 return (3 * 2): A
factorial(4) : n = 4 return (4 * 6) : A
factorial(5) : n = 5 return (5 * 24)
factorial(4) : n = 4 return (4 * factorial(3): A
factorial(3) : n = 3 return (3 * factorial(2): A
factorial(2) : n = 2 return (2 * factorial(1): A
factorial(1) : n = 1 return (1 * factorial(0): A
factorial(0) : n = 0 return (1): A
factorial(1) : n = 1 return (1 * 1): A
if (n == 0) return (1); else return ( n * factorial(n - 1) ); // A
Reverse String Display
H E L L O
O L L E H L L E HO
H E L L OFirst character first
H E L L OLast character first
rev(ello)•H o•rev(Hell)
reverse(in s:string) if (string is empty)
do nothing else { reverse(s minus the first character) display first character in the string }
First Character First
String Outputcat att"" t ta tac
reverse(in s:string) if (string is empty)
do nothing else { display last character in the string reverse(s minus the last character)}
Last Character First
String Outputcat tca ta c tac ""
void DisplayString(string str) { uint len = str.length(); ! if (len != 0) { cout << str[len - 1]; DisplayString(str.substr(0, len – 1)); } }
Code: Reverse Display
f(n) = f(n-1) + f(n-2) for n>2 f(2) = 1 f(1) = 1
!! The base case here is the value 1 for the first two fibonacci numbers. !!
! The recursive step is a combination of f(n-1) and f(n-2).
Fibonacci
double Fib(const int n) { // base case if (n <= 2) { return (1); } else { // recursive step return ( Fib(n - 1) + Fib(n - 2) ); } }
Code: Fibonacci
Fibonacci Traced
fib(6) = fib(5) + fib(4)
2
2 23
35
8
fib(5) = fib(4) + fib(3)
fib(4) = fib(3) + fib(2)
fib(3) = fib(2) + fib(1)
1 fib(2) = 1 1fib(1) = 1
fib(2) = 1 1
fib(3) = fib(2) + fib(1)
fib(2) = 11 fib(1) = 1 1
fib(4) = fib(3) + fib(2)
fib(3) = fib(2) + fib(1)
fib(2) = 11 fib(1) = 1 1
fib(2) = 1 1
Find Min
2 1 4 5 0
2 1 4 5 0 min(2,1,4,5) <? 0
2 1 4 5 min(2,1,4) <? 5
2 1 4 min(2,1) <? 4
2 1 min(2) <?
2 min(2)
if (array has only one item) min(array) is that itemelse min(array) is the smallest of the first item and min(array minus first item)
listType FindMin(const list ilist, const int len) { if (len == 1) { return (ilist[len - 1]); } else { listType cur = ilist[len - 1]; listType min = FindMin(ilist, len - 1); return ( (min < cur)? min : cur); } }
Code: FindMin
binarySearch(in anArray:ArrayType, in value:ItemType) if (anArray is of size 1)
Determine if anArray's item is equal to valueelse { Find the midpoint of anArray Determine which half of anArray contains values if (value is in the first half of anArray) binarySearch(first half of anArray, value) else binarySearch(second half of anArray, value)}
Binary Search
bool BinarySearch(const ilist list, const int first, const int last, const listType key, int& posFound) { int mid = (first + last) / 2; // base case if (last < first) { return (false); } else if (key == list[mid]) { posFound = mid; return (true); }
Code: BinarySearch
else if (key < list[mid]) { // key in lower half return (BinarySearch(list, first, mid - 1, key, posFound)); } else { // key in upper half return (BinarySearch(list, mid + 1, last, key, posFound)); } }
Code: BinarySearch
Binary Search Traced
binarySearch(-4, -2, -1, 3, 5, 6, 15, 21, 25): key = -1first:0 last:8 mid:4 arr[mid]:5 posFound:?
T
binarySearch(-4, -2, -1, 3): key = -1first:0 last:3 mid:1 arr[mid]:-2 posFound:?
binarySearch(-1, 3): key = -1first:2 last:3 mid:2 arr[mid]:-1 posFound:2
T
T
Towers of Hanoi
!You have three poles and n disks. ! The disks are of different size with the largest at the bottom. !
! The challenge is to move all the disks, from a source pole to a destination pole, using the third pole as a holding place. !
! A disk of a larger size cannot be on top of a disk of a smaller size. !
! Assume towers(n, A, B, C) is our initial problem of moving n disks from the source pole, A, to the destination pole B, using pole C as a place holder.
!towers(n-1,A,C,B)towers(1,A,B,C)towers(n-1,C,B,A)
void towers(const int n, const char source, const char destination, const char spare) { if (n == 1) { cout << "Move from " << source << " to " << destination << endl; } else { towers(n - 1, source, spare, destination); towers(1, source, destination, spare); towers(n - 1, spare, destination, source); } }
Code: Towers
int image[16][16] = { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1}, {1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1}, {1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1}, {1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1}, {1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1}, {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0}, {0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0}, {0,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1}, {0,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1}, {0,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1}, {1,0,0,1,1,0,1,1,0,1,1,1,1,0,1,1}, {1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1}, {1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1}, };
Code: FloodFill
void DisplayImage(void); void FloodFill (int x, int y); bool Filled(int x, int y); void Color(int x, int y); !void main(void) { DisplayImage(); FloodFill(6, 6); DisplayImage(); } !void FloodFill (int x, int y) { if ( !Filled(x, y) ) { Color(x, y); FloodFill(x-1, y); // left FloodFill(x+1, y); // right FloodFill(x, y-1); // up FloodFill(x, y+1); // down } }
Code: FloodFill
!!void DisplayImage(void) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { cout << image[y][x]; } cout << endl; } cout << endl << endl; }
Code: FloodFill
!!bool Filled(int x, int y) { bool isFilled = true; ! cout << "Checking: " << y << "," << x << endl; if (image[y][x] == 1) { isFilled = false; } return (isFilled); } !!void Color(int x, int y) { image[y][x] = 0; }
Code: FloodFill
! Recursion is very elegant, but can also be very inefficient. !
! Recursion can be inefficient for two reasons: ! The overhead associated with function calls. ! The inefficiency of the solution itself (see the fibonacci
example). !
! Basically, use recursion when there is no elegant iterative solution, and the recursive solution is not cost prohibitive.
Closing Remarks