Fundamentals of Computer Science II (CSC-152 97F)

[News] [Basics] [Syllabus] [Outlines] [Assignments] [Examples] [Readings] [Bailey Docs]

# Outline of Class 19: Recursion

## Recursion

• As those of you who took the scheme-based 151 know, recursive expression of algorithms is often the most natural.
• A typical recursive algorithm has
• A base case: what to do for simple inputs
• A recursive case: what to do for more complex inputs, involves a call to the same algorithm, using a simpler input.
• In pseudocode,
public returnType recursiveAlgorithm(someType input) {
someType simpler_input;

if (baseCase(input)) {
return baseComputation(input);
}
else {
simpler_input = simplify(input);
return computation(input, recursiveAlgorithm(simpler_input));
} // recursive case
} // recursiveAlgorithm

• For example, to express a solution to n!, the factorial of n, we might write:
public int factorial(int n) {
if (n == 0) {
return 1;
}
else {
return n*factorial(n-1);
}
} // factorial

Note that this almost precisely mimics the way in which a mathematician might define factorial over the integers.
• Some people view recursion simply as a mechanism for looping. While it is that, it is also a way of attacking problems.
• It is often the case that a recursive algorithm is more efficient than the corresponding looping algorithm (at least for "first designs" of algorithms).
• Consider the problem of computing x^n for some integers x and n.
• Nonrecursive:
/**
* Compute x^n for integers x and n
* pre: n >= 0
* pre: x > 0
* pre: x^n < maxint (can't really check this, but ...)
* post: returns x^n
*/
public int exp(int x, int n) {
int result = 1;	// The result, computed as we go
for(int i = 0; i < n; ++i) {
result *= x;
}
return result;
} // exp

• This has a running time of O(n)
• Recursive:
public int exp(int x, int n) {
int tmp;	// Temporary value, used for int. calcs.
if (n == 0) {
// x^0 = 1 for x != 0
return 1;
} // n is 0
else if (even(n)) {
// x^(2k) = x^k * x^k
tmp = exp(x, n/2);
return tmp*tmp;
} // n is even
else { // n is odd
// x^(k+1) = x * x^k
tmp = exp(x, n-1);
return x*tmp;
} // n is odd
} // exp

### Mutual recursion

• Sometimes, we write mutually-recursive algorithms, in which one algorithm call another, which calls the first, and they go back-and-forth until reaching a base-case.
• These algorithms are still considered recursive, and you use similar analysis techniques to determine their running times.

## The "minimum stamps" example

• Bailey illustrates some recursive principles with an algorithm that computes the minimum number of stamps that make up a particular value.

• Here's one algorithm for computing the minimum number of stamps needed to make up a particular price.
• For each stamp value, you assume that you can use one stamp of that value, and then compute the minimum number of stamps for the remaining price.
• If you minimize this count over all values, you get the minimum count.
• Here's a version of the algorithm in java
public int minimum_stamps(int price, int[] counts) {
int min = -1;       // The minimum
int submin;         // The minimum for a smaller price
int[] subcounts = new int[stamp_values.length];
// Counts for smaller price

// Sanity check
if (price == 0) {
for(int i = 0; i < stamp_values.length; ++i) {
counts[i] = 0;
} //for
return 0;
}

// Try each stamp value
for(int i = 0; i < stamp_values.length; ++i) {
if (price >= stamp_values[i]) {
submin = minimum_stamps(price-stamp_values[i],subcounts);
// If it's a valid number of stamps, and "better" than our
// previous best, update our best
if ( (submin > -1) &&
( (submin+1 < min) || (min == -1) ) ) {
min = submin+1;
for(int j = 0; j < stamp_values.length; ++j) {
counts[j] = subcounts[j];
} // for
counts[i] += 1;
} // A better value
} // if the value is smaller than the price
} // for
// That's it, we're done
return min;
} // minimum_stamps

• Unfortunately, this is a relatively inefficient algorithm. Why? Consider the task of computing how many stamps are needed to make up 10 cents, using 1, 2, and 5 cent stamps.
• That's 1 + (calls to solve 10-1 = 9 cents) + (calls to solve 10-2 = 8 cents) + (calls to solve 10-2 = 5 cents)
• Calls to solve 9 cents: 1 + (calls to solve 9-1 = 8 cents) + (calls to solve 9-2 = 7 cents) + (calls to solve 9-5 = 4 cents)
• Calls to solve 8 cents: 1 + (calls to solve 8-1 = 7 cents) + (calls to solve 8-2 = 6 cents) + (calls to solve 8-5 = 3 cents)
• Calls to solve 7 cents: 1 + (calls to solve 7-1 = 6 cents) + (calls to solve 7-2 = 5 cents) + (calls to solve 7-5 = 2 cents)
• Calls to solve 6 cents: 1 + (calls to solve 6-1 = 5 cents) + (calls to solve 6-2 = 4 cents) + (calls to solve 6-5 = 1 cent)
• Calls to solve 5 cents: 1 + (calls to solve 5-1 = 4 cents) + (calls to solve 5-2 = 3 cents) + (calls to solve 5-5 = 0 cents)
• Calls to solve 4 cents: 1 + (calls to solve 4-1 = 3 cents) + (calls to solve 4-2 = 2 cents)
• Calls to solve 3 cents: 1 + (calls to solve 3-1 = 2 cents) + (calls to solve 3-2 = 1 cent)
• Calls to solve 2 cents: 1 + (calls to solve 2-1 = 1 cent) + (calls to solve 2-2 = 0 cents)
• Calls to solve 1 cent: 1 + (calls to solve 1-1 = 0 cents)
• Calls to solve 0 cents: 1
• Working our way back up
• Calls to solve 0 cents: 1
• Calls to solve 1 cent: 2
• Calls to solve 2 cents: 4 (= 1 + 2 + 1)
• Calls to solve 3 cents: 7 (= 1 + 4 + 2)
• Calls to solve 4 cents: 12 (= 1 + 7 + 4)
• Calls to solve 5 cents: 21 (= 1 + 12 + 7 + 1)
• Calls to solve 6 cents: 36 (= 1 + 21 + 12 + 2)
• Calls to solve 7 cents: 62 (= 1 + 36 + 21 + 4)
• Calls to solve 8 cents: 106 (= 1 + 62 + 36 + 7)
• Calls to solve 9 cents: 181 (= 1 + 106 + 62 + 12)
• Calls to solve 10 cents: 309 (= 1 + 181 + 106 + 21)
• That's disgustingly large. Can you come up with an approximation?
• It's also inefficient, as we are clearly repeating work.
• There are a number of strategies for avoiding repeated work.

Outlines: prev next

[News] [Basics] [Syllabus] [Outlines] [Assignments] [Examples] [Readings] [Bailey Docs]

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.