0% found this document useful (0 votes)
17 views

chapter_10

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

chapter_10

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Basic Recursions

• Break a problem into smaller identical problems


– Each recursive call solves an identical but smaller
problem.
• Stop the break-down process at a special case whose
solution is obvious, (termed a base case)
case
– Each recursive call tests the base case to
eventually stop.
– Otherwise, we fall into an infinite
recursion.
Example 1: The Sum of the First N
Positive Integers
• Definition:
sum(n) = n + (n-1) + (n-2) + … + 1 for any integer n > 0
• Recursive relation;
sum(n) = n + [(n-1) + (n-2) + … + 1]
= n + sum(n-1)
Looks so nice, but how about n == 1?
sum(1) = 1 + sum(0), but the argument to sum( ) must be
positive
• Final recursive definition:
sum(n) = 1 if n = 1 (Base case)
= n + sum(n-1) if n > 1 (Recursive call)
Recursive Definition of sum(n)
int sum(int n)
{
if (n == 1) // base case
return 1;
else
return n + sum(n-1); // recursive call A
}

How should I test this function’s correctness?


Use the box method:
A box has each function’s local environment ex. cout << sum(3);

1. Arguments n=3
2. Local variables
3. Place holder for the value A: sum(n-1) = ?
returned by a called function
4. A return value return ?
Box trace of sum(3)
cout << sum(3);
n=3 n=2 n=1
A: sum(n-1)=? A: sum(n-1)=?
return ? return ? return 1

n=3 n=2 n=1


A: sum(n-1)= 3? 1
A: sum(n-1)=?
return ?6 return 3? return 1

Each box corresponds to a function’s activation record or stack.


Example 2: The Factorial of n
• Definition:
factorial(n) = n * (n-1) * (n-2) * … * 1 for any integer n > 0
factorial(0) = 1
• Recursive relation;
factorial(n) = n * [(n-1) * (n-2) * … * 1]
= n * factorial(n-1)
Looks so nice, but how about n = 1?
factorial(1) = 1 * factorial(0) but the argument to factorial( )
must be positive
• Final recursive definition:
factorial(n) =1 if n = 1
= n *factorial(n-1) if n > 1
Basic Recursions

Recursive Definition of facotrial(n)


int fact(int n)
{
if (n == 1) // base case
return 1;
else
return n * fact(n-1); // recursive call A
}

Trace its execution using the box method:


ex. cout << fact(3);

n=3

A: fact(n-1) = ?

return ?
CSS342: Recursion 6
Box trace of fact(3)
cout << fact(3);
n=3 n=2 n=1
A: fact(n-1)=? A: fact(n-1)=?
return ? return ? return 1

n=3 n=2 n=1


A: fact(n-1)= 2? A: fact(n-1)=?1
return ? 6 return ? 2 return 1
Precondition of fact(n)
• Precondition: n >= 1
• If the precondition is violated, what happen?
– Fact(0) calls fact(-1), which calls fact(-2), ….
• For robustness, given a negative number or 0, fact should stop a
recursive call.

Always correct to recursions


int fact(int n)
{
if (n <= 1) // base case for n = 1 or bad args.
return 1;
else
return n * fact(n-1); // recursive call A
}
Another example:
n choose k (combinations)
• Given n things, how many different sets of
size k can be chosen?

n n-1 n-1
= + , 1 < k < n (recursive solution)
k k k-1
n n!
= , 1 < k < n (closed-form solution)
k k!(n-k)!
with base cases:
n n
= n (k = 1), = 1 (k = n)
1 n
n choose k (combinations)
int Combinations(int n, int k)
{
if(k == 1) // base case 1
return n;
else if (n == k) // base case 2
return 1;
else
return(Combinations(n-1, k) + Combinations(n-1, k-1));
}
Tower of Hanoi
• Pole A with heavy metal disks of various
sizes stacked on top of each other.
• Objective: Transfer disks from Pole A to
Pole B.
• Constraint: Disks are so heavy that stacking
to be done with largest at the bottom and in
order.
• Support: You may use a spare pole during
transfer.
Towers of Hanoi

A B C

Find how to move dishes from A to B using C.


Restrictions:
Solution
In order to move n dishes from move(n, A, B, C)
A to B via C,
A B C
if we could move n-1 dishes
move(n-1, A, C, B)
from A to C via B,
A B C
we could move a dish, (i.e.,
the last one) from A to B (via C), move(1, A, B, C)
A B C
and thereafter, we would move n-1
Dishes from C to B via A! move(n-1, C, B, A)
A B C
Example Code
#include <iostream>
#include <stdlib.h>
using namespace std;

void move( int n, char orig, char dest, char temp ) {


if ( n == 1 )
cout << "move disk 1 from " << orig << " to " << dest << endl;
else {
move( n - 1, orig, temp, dest );
cout << "move disk " << n << " from " << orig << " to " << dest << endl;
move( n - 1, temp, dest, orig );
}
}

int main( int argc, char* argv[] ) {

int nDishes = atoi( argv[1] );


move( nDishes, 'A', 'B', 'C' );

cout << "completed" << endl;


return 0;
}
Tracing move(n, A, B, C)
move(3, A, B, C)

4
move(2, A, C, B) move(1, A, B, C) move(2, C, B, A)
Locally, A is A, C is B, B is C. Locally C is A, B is B, A is C.

1
move(1, A, B, C) 5 move(1, C, A, B)
2 6
move(1, A, C, B) move(1, C, B, A)

3 7
move(1, B, C, A) move(1, A, B, C)
Recursion vs. iteration
• Iteration can be used in place of recursion
– An iterative algorithm uses a looping construct
– A recursive algorithm uses a branching structure
• Recursive solutions are often less efficient, in
terms of both time and space, than iterative
solutions
• Recursion can simplify the solution of a problem,
often resulting in shorter, more easily understood
source code

You might also like