
Week 4, Monday
January 26, 2026
We computed \(1 + 2 + 3 + \ldots + n\) recursively:

The mathematical decomposition: \(f(n) = 2 \cdot f(\lfloor n/2 \rfloor) + (n - \lfloor n/2 \rfloor)^2\)
Both compute the same answer. But are they equally fast?
| Code | How many recursive calls? |
|---|---|
2 * triangle_fast(half) |
ONE call, multiply result by 2 |
triangle_double(half) + triangle_double(half) |
TWO calls! |
The mathematical relationship is: \(f(n) = 2 \cdot f(\lfloor n/2 \rfloor) + (n - \lfloor n/2 \rfloor)^2\)
But the time to compute depends on how many recursive calls we make!
When we write recursive code, how do we figure out its running time?
The answer: We write a recurrence relation for \(T(n)\), the time.
triangle_fast: \(T(n) = T(n/2) + O(1)\) — ONE calltriangle_double: \(T(n) = 2T(n/2) + O(1)\) — TWO callsDifferent recurrences → different running times!
Let’s explore this through another recursive puzzle…

Both inputs are sorted
The output contains all elements from both inputs
The output is sorted
The function: Given two sorted lists, produce one sorted list with all elements.
What’s the simplest case?

What if both lists have elements?

The smallest element overall must be at the front of one of the lists!
Each recursive call: processes one element.
How many calls? Exactly \(n\) (total elements).
Running time: \(O(n)\)
Induction on the total size \(n = |left| + |right|\).
Base cases: If either list is empty, return the other. ✓
Inductive step: Assume merge works for total size \(< n\).

Inductive step: Given sorted lists left and right with total size \(n\):
left[0] and right[0] (the two minima)Therefore, merge is correct for all inputs. ∎

Testing shows it works on examples. But how do we prove it always works?
Induction on the size of the input:

A list with 0 or 1 elements is already sorted. ✓
Assume: merge_sort correctly sorts any list of size \(< n\).
Goal: Show merge_sort correctly sorts a list of size \(n\).
By our assumption, left_sorted and right_sorted are correctly sorted.
Thus they are valid inputs to merge.
We have already proved correctness of merge, so we are done!
merge_sort works for sizes \(< n\)left_sorted is sorted (by IH, since size \(< n\))right_sorted is sorted (by IH, since size \(< n\))merge combines them correctly (by earlier proof)merge_sort works for size \(n\) ✓By induction, merge_sort is correct for all \(n\). ∎