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

chapter_10

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views

chapter_10

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
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