420 likes | 582 Views
Recursion. Chapter 12. 12.1 Nature of Recursion. Problems that lend themselves to a recursive solution have the following characteristics: One or more simple case of the problem have a straightforward, non-recursive solution
E N D
Recursion Chapter 12
12.1 Nature of Recursion • Problems that lend themselves to a recursive solution have the following characteristics: • One or more simple case of the problem have a straightforward, non-recursive solution • Otherwise, use reduced cases of the problem that are closer to a stopping case • Eventually the problem can be reduced to stopping cases only. Easy to solve
Nature of Recursion Splitting a problem into smaller problems Size n Problem Size n-1 Problem Size n-2 Problem Size 1 problem Size 1 problem Size 1 problem
Power by Multiplication • Raise 6 to the power of 3 • Raise 6 to the power of 22 • Multiply the result by 6 • Raise 6 to the power of 2 • Raise 6 to the power of 1 • Multiply the result by 6 • Multiplying 6 * 6 * 6
Power.cpp // FILE: Power.cpp // RECURSIVE POWER FUNCTION // Raises its first argument to the power // indicated by its second argument. // Pre: m and n are defined and > 0. // Post: Returns m raised to power n. int power (int m, int n) { if (n <= 1) return m; else return m + power (m, n - 1); }
12.2 Tracing Recursive Functions • Hand tracing we see how algorithm works • Very useful in recursion • Previous Multiply example trace • “Activation Frame” corresponds to a function call • Darker shading shows the depth of recursion
Recursive Function with No Return Value • If statement with some stopping condition • n <= 1; • When TRUE stopping case is reached • recursive step is finished • falls back to previous calls (if any) • trace of reverse • ReverseTest.cpp
ReverseTest.cpp #include <iostream> using namespace std; void reverse(); int main () { reverse(); cout << endl; return 0; }
ReverseTest.cpp void reverse() { char next; cout << "Next character or * to stop: "; cin >> next; if (next != ‘*’) { reverse(); cout << next; } }
Argument and Local Variable Stacks • How does C++ keep track of n and next ? • Uses a data structure called a stack • Think of a stack of trays in a cafeteria • Each time a function is called it is pushed onto the stack • Only top values are used when needed (popping) • Example of calls to reverse
Recursive String • After 1st call to reverse n next 3 ? top • c is read into next just prior to 2nd call n next 3 c top
Recursive String • After 2nd call to reverse n next 2 ? top 3 c • letter a is read into next just prior to 3rd call n next 2 a top 3 c
Recursive String • After 3rd call to reverse n next 1 ? top 2 a 3 c • letter t is read into next printed due to stop case n next 1 t top 2 a 3 c
Recursive String • After 1st return n next 2 a top 3 c • After 2nd return n next 3 c • After 3rd return (final) ? ?
12.3 Recursive Mathematical Functions • Many mathematical functions are defined recursively • factorial n! of a number • 0! = 1 • n! = n * *n-1)! for n > 0 • So 4! = 4 * 3 * 2 * 1 or 24 • Look at a block of recursive math function example source code files
Factorial.cpp // FILE: Factorial.cpp // RECURSIVE FACTORIAL FUNCTION // COMPUTES N! int factorial (int n) { if (n <= 0) return 1; else return n * factorial (n-1); }
FactorialI.cpp // FILE: FactorialI.cpp // ITERATIVE FACTORIAL FUNCTION // COMPUTES N! int factorialI (int n) { int factorial; factorial = 1; for (int i = 2; i <= n; i++) factorial *= i; return factorial; }
Fibonacci.cpp // FILE: Fibonacci.cpp // RECURSIVE FIBONACCI NUMBER FUNCTION int fibonacci (int n) // Pre: n is defined and n > 0. // Post: None // Returns: The nth Fibonacci number. { if (n <= 2) return 1; else return fibonacci (n - 2) + fibonacci (n - 1); }
GCDTest.cpp // FILE: gcdTest.cpp // Program and recursive function to find // greatest common divisor #include <iostream> using namespace std; // Function prototype int gcd(int, int);
GCDTest.cpp int main() { int m, n; // the two input items cout << "Enter two positive integers: "; cin >> m >> n; cout << endl; cout << "Their greatest common divisor is " << gcd(m, n) << endl; return 0; }
GCDTest.cpp // Finds the greatest common divisor of two // integers // Pre: m and n are defined and both are > 0. // Post: None // Returns: The greatest common divisor of m and // n. int gcd(int m, int n) { if (m < n) return gcd(n, m);
GCDTest.cpp else if (m % n == 0) return n; else return gcd(n, m % n); // recursive step }
GCDTest.cpp Program Output Enter two positive integers separated by a space: 24 84 Their greatest common divisor is 12
12.4 Recursive Functions with Array Arguments // File: findSumTest.cpp // Program and recursive function to sum an // array's elements #include <iostream> using namespace std; // Function prototype int findSum(int[], int); int binSearch(int[], int, int, int);
FindSumTest.cpp int main() { const int SIZE = 10; int x[SIZE]; int sum1; int sum2; // Fill array x for (int i = 0; i < SIZE; i++) x[i] = i + 1;
FindSumTest.cpp // Calulate sum two ways sum1 = findSum(x, SIZE); sum2 = (SIZE * (SIZE + 1)) / 2; cout << "Recursive sum is " << sum1 << endl; cout << "Calculated sum is " << sum2 << endl; cout << binSearch(x, 10, 10, SIZE-1) << endl; return 0; }
FindSumTest.cpp // Finds the sum of integers in an n-element // array int findSum(int x[], int n) { if (n == 1) return x[0]; else return x[n-1] + findSum(x, n-1); }
FindSumTest.cpp // Searches for target in elements first through // last of array // Precondition : The elements of table are // sorted & first and last are defined. // Postcondition: If target is in the array, // return its position; otherwise, returns -1. int binSearch (int table[], int target, int first, int last) { int middle;
FindSumTest.cpp middle = (first + last) / 2; if (first > last) return -1; else if (target == table[middle]) return middle; else if (target < table[middle]) return binSearch(table, target, first, middle-1); else return binSearch(table, target, middle+1, last); }
12.5 Problem Solving with Recursion • Case Study: The Towers of Hanoi • Problem Statement • Solve the Towers of Hanoi problem for n disks, where n is the number of disks to be moved from tower A to tower c • Problem Analysis • Solution is a printed list of each disk move. Recursive function that can be used to move any number of disks from one tower to the other tower.
Towers of Hanoi • Program Design • If n is 1 • move disk 1 from fromTower to toTower • else • move n-1 disks from fromTower to aux tower using the toTower • move disk n from the fromTower to the toTower • move n-1 disks from aux tower to the toTower using fromTower
Towers of Hanoi • Program Implementation • Towers.cpp • Program Verification & Test • towers (‘A’, ’C’, ‘B’, 3); • Towers trace
Tower.cpp // File: tower.cpp // Recursive tower of hanoi function #include <iostream> using namespace std; void tower(char, char, char, int); int main() { int numDisks; // input - number of disks
Tower.cpp cout << "How many disks: "; cin >> numDisks; tower('A', 'C', 'B', numDisks); return 0; } // Recursive function to "move" n disks from // fromTower to toTower using auxTower // Pre: The fromTower, toTower, auxTower, and // n are defined. // Post: Displays the required moves.
Tower.cpp void tower (char fromTower, char toTower, char auxTower, int n) { if (n == 1) cout << "Move disk 1 from tower " << fromTower << " to tower " << toTower << endl; else {
Tower.cpp tower(fromTower, auxTower, toTower, n-1); cout << "Move disk " << n << " from tower "<< fromTower << " to tower " << toTower << endl; tower(auxTower, toTower, fromTower, n-1); } } // end tower
TowerTest.cpp Program Output Move disk 1 from tower A to tower C Move disk 2 from tower A to tower B Move disk 1 from tower C to tower B Move disk 3 from tower A to tower C Move disk 1 from tower B to tower A Move disk 2 from tower B to tower C Move disk 1 from tower A to tower C
12.6 Common Programming Errors • Stopping conditions • Missing return statements • Optimizations • recursion of arrays use large amounts of memory • use care when tracing your solutions