CSE 40872 Lecture 015

Topic:Recursion (Iteration)
Author: Peter Bui <pbui@cse.nd.edu>
Date: October 5, 2009

Recursion

Recursive algorithms have two types of cases:

  1. Base cases: ends or limits recursion.

  2. Recursive cases: reuses solution to solve subproblem.

Recursion is used in a variety of programming techniques and data structures.

Divide and Conquer

1. Break a problem into two or more sub-problems of the same type, until these are simple enough to be solved directly.

  1. Once these are solved, combine the results to form the final solution.

Consider QuickSort or MergeSort or DFS.

Trees

The definition of a tree is inherently recursive:

struct Node
{
    void        *value;
    struct Node *left;
    struct Node *right;
};

This leads to recursive definitions of functions that operate on trees.

Problems

Each recursive call requires saving local variables and registers to the program stack. Deep recursion can run into the stack limit and blow up the program.

Example

#define STACK_LIMIT 1000000

int f(int i) {
    if (i <= STACK_LIMIT)
        return f(i + 1);
    else
        return 1;
}
int main(int argc, char *argv) {
        return f(0);
}

Tail Recursion

To avoid using up stack space, we can use a technique called Tail Recursion that basically turns each recursive call into a goto. This is used in languages like Scheme, ML to optimize the use of recursion.

To do so, you basically have to make the implicit accumulator explicit.

Example

int factorial(int n) {
    int acc = 1;

factorial_repeat:
    if (n <= 1)
        goto factorial_finish;
    else
        acc *= n--;
    goto factorial_repeat;

factorial_finish:
    return (acc);
}

Iteration

Many times, simple recursion can be implemented using iteration or looping. Since no stack allocation is required, these solutions tend to be more efficient. Moreover, more complex recursive algorithms can be implemented without recursive calls by using an explicit stack.

Many normally recursive algorithms such as QuickSort have complex but fast and efficient iterative implementations.

Example

int factorial(int n) {
    int acc = 1;

    while (n <= 1)
        acc *= n--;

    return (acc);
}

Summary

Recursion is a powerful and useful programming concept. Sometimes the easiest and most straightforward solution is through using recursion. You have to be careful though of your stack limit, and in some cases it may be more efficient to use iteration or loops.