Ch6.11: Recursive Functions

Overview

A recursive function is a function that calls itself. Recursion is a natural way to express problems that can be broken down into smaller subproblems of the same form.

In this chapter, you will learn:

1. What is recursion?

A recursive function solves a problem by solving a smaller version of the same problem. Every recursive function must have:

Without a base case, recursion never ends and the program eventually crashes due to stack exhaustion.

2. Example: factorial

The factorial function is defined mathematically as:


n! = n × (n - 1)!  
0! = 1
      

This definition is naturally recursive.


int factorial(int n)
{
    if(n < 0)
        ::fast_io::fast_terminate(); // factorial is undefined for negatives

    if(n == 0)
        return 1;                    // base case

    return n * factorial(n - 1);     // recursive case
}

Each call reduces the problem until it reaches the base case.

3. How recursion uses the call stack

Every function call creates a new stack frame containing:

Recursive functions create one stack frame per recursive call. For example:


factorial(4)
 ├─ factorial(3)
 │   ├─ factorial(2)
 │   │   ├─ factorial(1)
 │   │   │   └─ factorial(0)

When the base case returns, the stack unwinds in reverse order.

If recursion goes too deep, the program will crash due to stack overflow.

4. Tail recursion

A tail-recursive function is one where the recursive call is the last operation in the function.


int sum_tail(int n, int acc)
{
    if(n == 0)
        return acc;          // base case

    return sum_tail(n - 1, acc + n); // tail call
}

In some languages, tail recursion is optimized into a loop. However:

C++ does not guarantee tail-call optimization.

Compilers may optimize tail recursion, but you must not rely on it. If you need guaranteed constant stack usage, write an explicit loop instead.

5. When recursion is appropriate

Recursion is a good fit when:

Recursion is a poor fit when:

6. More examples

6.1 Fibonacci (inefficient recursive version)


int fib(int n)
{
    if(n < 0)
        ::fast_io::fast_terminate();

    if(n <= 1)
        return n;

    return fib(n - 1) + fib(n - 2);
}

This version is extremely slow because it recomputes values repeatedly. Iterative or memoized versions are better.

Key takeaways