Recursion and Recurrence Relations

How recursive calls run, and how to find their running time with recursion trees and the master theorem.

A recursive function solves a problem by calling itself on smaller inputs. Every recursive function needs:

  • a base case that is answered directly, and
  • a recursive case that makes progress towards the base case.

Each call gets its own stack frame with its own local variables. The frames pile up on the call stack until a base case returns, and then unwind in reverse order. A recursion that is d calls deep uses O(d) stack space.

Tower of Hanoi

Move n discs from peg A to peg C, one disc at a time, never putting a larger disc on a smaller one. The recursive idea: move n − 1 discs out of the way to B, move the biggest disc to C, then move the n − 1 discs from B onto it.

hanoi(n, from, to, via)n == 0?YesNoreturn (nothing to move)hanoi(n-1, from, via, to)move disc n: from → tohanoi(n-1, via, to, from)return
hanoi(n, from, to, via)
public class Main {
    static int moves = 0;
    static boolean show = true;

    static void hanoi(int n, char from, char to, char via) {
        if (n == 0) return;
        hanoi(n - 1, from, via, to);
        moves++;
        if (show) System.out.println("move disc " + n + ": " + from + " -> " + to);
        hanoi(n - 1, via, to, from);
    }

    public static void main(String[] args) {
        hanoi(3, 'A', 'C', 'B');
        System.out.println("moves for 3 discs: " + moves);
        moves = 0;
        show = false;
        hanoi(10, 'A', 'C', 'B');
        System.out.println("moves for 10 discs: " + moves);
    }
}
Output
move disc 1: A -> C
move disc 2: A -> B
move disc 1: C -> B
move disc 3: A -> C
move disc 1: B -> A
move disc 2: B -> C
move disc 1: A -> C
moves for 3 discs: 7
moves for 10 discs: 1023

The number of moves satisfies M(n) = 2M(n − 1) + 1 with M(0) = 0, whose solution is M(n) = 2ⁿ − 1.

Recurrence relations

The running time of a recursive algorithm is naturally written as a recurrence: the time for size n in terms of the time for smaller sizes.

AlgorithmRecurrenceSolution
Binary searchT(n) = T(n/2) + O(1)Θ(log n)
Merge sortT(n) = 2T(n/2) + Θ(n)Θ(n log n)
Tower of HanoiT(n) = 2T(n − 1) + O(1)Θ(2ⁿ)
Linear recursion (e.g. factorial)T(n) = T(n − 1) + O(1)Θ(n)
Quick sort, worst caseT(n) = T(n − 1) + Θ(n)Θ(n²)

The recursion tree method

Draw the calls as a tree, write the work done at each node, and add up level by level. For merge sort, T(n) = 2T(n/2) + n:

nlevel 0: nn/2level 1: n/2 + n/2 = nn/4level 2: 4 × n/4 = nn/4n/2n/4n/4
Recursion tree for T(n) = 2T(n/2) + n: every level does n work, and there are log₂ n levels

Total = n × (number of levels) = n log₂ n, so T(n) = Θ(n log n).

The master theorem

For recurrences of the form T(n) = a·T(n/b) + f(n) with a ≥ 1 and b > 1, compare f(n) with n^(log_b a):

CaseConditionResult
1f(n) = O(n^(log_b a − ε)) for some ε > 0 (the leaves dominate)T(n) = Θ(n^(log_b a))
2f(n) = Θ(n^(log_b a) · logᵏ n), k ≥ 0 (every level equal)T(n) = Θ(n^(log_b a) · logᵏ⁺¹ n)
3f(n) = Ω(n^(log_b a + ε)) and a·f(n/b) ≤ c·f(n) for some c < 1 (the root dominates)T(n) = Θ(f(n))

Examples:

  • T(n) = 4T(n/2) + n: n^(log₂ 4) = n² beats n → case 1 → Θ(n²).
  • T(n) = 2T(n/2) + n: n^(log₂ 2) = n, same as f(n) → case 2 → Θ(n log n).
  • T(n) = 2T(n/2) + n²: f(n) = n² beats n → case 3 → Θ(n²).
  • T(n) = 7T(n/2) + n²: n^(log₂ 7) ≈ n^2.81 beats n² → case 1 → Θ(n^2.81) (Strassen's matrix multiplication).

The master theorem does not apply to recurrences like T(n) = T(n − 1) + n; use the recursion tree or substitution for those.

Reading recursive code

GATE often shows a short recursive function and asks what it returns. Trace the calls carefully, from the base case upwards.

public class Main {
    // returns the number of 1 bits in n
    static int ones(int n) {
        if (n == 0) return 0;
        return (n % 2) + ones(n / 2);
    }

    // f(n) = f(n-1) + 2 * f(n-2), f(0) = 0, f(1) = 1
    static int f(int n) {
        if (n <= 1) return n;
        return f(n - 1) + 2 * f(n - 2);
    }

    public static void main(String[] args) {
        System.out.println("ones(45) = " + ones(45));
        for (int n = 0; n <= 6; n++) System.out.print("f(" + n + ")=" + f(n) + " ");
        System.out.println();
    }
}
Output
ones(45) = 4
f(0)=0 f(1)=1 f(2)=1 f(3)=3 f(4)=5 f(5)=11 f(6)=21 

GATE-style practice questions

GATE-styleMCQ · one correct answer

What is the solution of the recurrence T(n) = 4T(n/2) + n² with T(1) = 1?

Show answer and explanationAnswer: B

Here a = 4, b = 2, so n^(log₂ 4) = n², exactly the same as f(n) = n². This is case 2 of the master theorem with k = 0, giving Θ(n² log n).

GATE-styleMCQ · one correct answer

What is the solution of T(n) = T(n − 1) + n with T(1) = 1?

Show answer and explanationAnswer: C

Unrolling gives T(n) = n + (n − 1) + ... + 1 = n(n + 1)/2 = Θ(n²). The master theorem does not apply because the subproblem is n − 1, not n/b.

GATE-styleNAT · numerical answer

How many moves does the Tower of Hanoi need for 8 discs?

Show answer and explanationAnswer: 255

M(n) = 2M(n − 1) + 1 with M(0) = 0 gives M(n) = 2ⁿ − 1 = 255.

GATE-styleNAT · numerical answer

Consider the function

int g(int n) { if (n <= 2) return 1; return g(n - 1) + g(n - 3); }

What does g(8) return?

Show answer and explanationAnswer: 13

Every call with n ≤ 2 returns 1, including the calls g(0) and below reached through g(n − 3). Building upwards: g(3) = g(2) + g(0) = 2, g(4) = g(3) + g(1) = 3, g(5) = g(4) + g(2) = 4, g(6) = g(5) + g(3) = 6, g(7) = g(6) + g(4) = 9 and g(8) = g(7) + g(5) = 13.