Post on 28-Dec-2015
Recursion
Chapter 12
2
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
3
Nature of Recursion
Splitting a problem into smaller problems
Size nProblem
Size n-1Problem
Size n-2Problem
Size 1problem
Size 1problem
Size 1problem
4
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
5
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);
}
6
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
7
Trace of Power
8
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
9
ReverseTest.cpp
#include <iostream>
using namespace std;
void reverse();
int main ()
{
reverse();
cout << endl;
return 0;
}
10
ReverseTest.cpp
void reverse()
{
char next;
cout << "Next character or * to stop: ";
cin >> next;
if (next != ‘*’)
{
reverse();
cout << next;
}
}
11
Reverse Trace
12
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
13
Recursive String
After 1st call to reversen next
3 ? top– c is read into next just prior to 2nd call
n next
3 c top
14
Recursive String
After 2nd call to reversen next
2 ? top
3 c– letter a is read into next just prior to 3rd call
n next
2 a top
3 c
15
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
16
Recursive String
After 1st returnn next
2 a top
3 c After 2nd return
n next
3 c After 3rd return (final)
? ?
17
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
18
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);
}
19
Factorial Trace
20
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;
}
21
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);
}
22
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);
23
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;
}
24
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);
25
GCDTest.cpp
else if (m % n == 0)
return n;
else
return gcd(n, m % n); // recursive step
}
26
GCDTest.cpp
Program Output
Enter two positive integers separated by a space: 24 84
Their greatest common divisor is 12
27
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);
28
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;
29
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;
}
30
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);
}
31
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;
32
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);
}
33
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.
34
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
35
Towers of Hanoi
Program Implementation– Towers.cpp
Program Verification & Test– towers (‘A’, ’C’, ‘B’, 3);
Towers trace
36
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
37
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.
38
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
{
39
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
40
Towers Trace
41
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
42
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