Divide and Conquer Trees
The Shape of the Tree IS the Complexity
Every divide-and-conquer algorithm builds a recursion tree. We saw this in the Master Theorem lesson. Now we'll look at three specific algorithms — merge sort, quicksort, and binary search — and show that the shape of their recursion trees directly determines their performance.
The punchline: a balanced tree gives you \(O(n \log n)\). A skewed chain gives you \(O(n^2)\). A single path gives you \(O(\log n)\). No formulas needed — just look at the tree.

Merge Sort: The Perfectly Balanced Tree
Merge sort always splits the array exactly in half. This produces a perfectly balanced binary tree.
For \(n = 8\) elements [8, 3, 5, 1, 4, 2, 7, 6]:
[8,3,5,1,4,2,7,6] merge: 8 comparisons
/ \
[8,3,5,1] [4,2,7,6] merge: 4+4
/ \ / \
[8,3] [5,1] [4,2] [7,6] merge: 2+2+2+2
/ \ / \ / \ / \
[8] [3] [5] [1] [4] [2] [7] [6] base cases
Each level of the tree processes all \(n\) elements exactly once (during the merge step). The tree has \(\log_2 8 = 3\) levels. Total work: \(n \cdot \log n = 24\).
The tree is balanced because merge sort controls the split point — it always picks the middle. No matter what the input looks like, the tree has the same shape. That's why merge sort is always \(O(n \log n)\).
| Level | Arrays being merged | Total elements processed |
|---|---|---|
| 3 (bottom) | 4 merges of size 2 | 8 |
| 2 | 2 merges of size 4 | 8 |
| 1 | 1 merge of size 8 | 8 |
Quicksort: The Random Tree
Quicksort partitions the array around a pivot. The pivot's position determines the split — and the split determines the tree shape.
Best Case: Balanced Split
If the pivot always lands in the middle, quicksort produces the same balanced tree as merge sort:
Balanced tree. \(O(n \log n)\).
Worst Case: Pivot Is Always the Smallest (or Largest)
If you always pick the minimum element as pivot (this happens with sorted input and "first element" pivot selection):
[1, 2, 3, 4, 5, 6, 7, 8]
[1] -> [2, 3, 4, 5, 6, 7, 8] partition: 8 comparisons
[2] -> [3, 4, 5, 6, 7, 8] partition: 7 comparisons
[3] -> [4, 5, 6, 7, 8] partition: 6 comparisons
... ...
[7] -> [8] partition: 2 comparisons
The tree degenerates into a chain — each node has only one non-empty child:
[1,2,3,4,5,6,7,8] work: 8
\
[2,3,4,5,6,7,8] work: 7
\
[3,4,5,6,7,8] work: 6
\
[4,5,6,7,8] work: 5
\
[5,6,7,8] work: 4
\
[6,7,8] work: 3
\
[7,8] work: 2
\
[8] work: 1
Total work: \(8 + 7 + 6 + \cdots + 1 = \frac{n(n+1)}{2} = 36\). That's \(O(n^2)\).
Side-by-Side Comparison for n = 8
| Property | Balanced tree | Chain |
|---|---|---|
| Depth | \(\log_2 8 = 3\) | \(8 - 1 = 7\) |
| Work at level \(d\) | \(\approx n\) | \(n - d\) |
| Total work | \(n \log n = 24\) | \(n(n+1)/2 = 36\) |
| Complexity | \(O(n \log n)\) | \(O(n^2)\) |
Same algorithm, different tree shapes, different complexities. Randomized pivot selection makes the balanced case overwhelmingly likely — the expected depth is \(O(\log n)\).
Binary Search: A Path, Not a Tree
Binary search doesn't branch. At each step, you go left OR right — never both. The "recursion tree" is a single path from root to leaf.
Searching for 5 in [1, 2, 3, 4, 5, 6, 7, 8]:
[1,2,3,4,5,6,7,8] mid=4, target>4, go right
\
[5,6,7,8] mid=6, target<6, go left
/
[5] mid=5, target==5, found
Three comparisons. The path has length \(\log_2 8 = 3\).
This is also why binary search IS a path in a BST. If you built a balanced BST from [1, 2, 3, 4, 5, 6, 7, 8]:
Searching for 5: start at 4, go right to 6, go left to 5. The exact same path.
Binary search = walking a path from root to target in an implicit balanced BST. The array is the BST, the midpoint formula gives you the root of each subtree, and going left/right in the array is going left/right in the tree.
The Unifying View
| Algorithm | Tree shape | Branching | Depth | Work per level | Total |
|---|---|---|---|---|---|
| Merge sort | Balanced binary | 2 children | \(\log n\) | \(n\) | \(O(n \log n)\) |
| Quicksort (best) | Balanced binary | 2 children | \(\log n\) | \(n\) | \(O(n \log n)\) |
| Quicksort (worst) | Chain | 1 child | \(n\) | \(n - d\) | \(O(n^2)\) |
| Binary search | Path | 1 child | \(\log n\) | \(O(1)\) | \(O(\log n)\) |
The tree shape encodes everything:
- Depth = how many levels of recursion = the \(\log n\) or \(n\) factor.
- Width = how much work per level = the \(n\) or \(O(1)\) factor.
- Balance = whether the algorithm is efficient or degenerate.
When someone asks "why is merge sort \(O(n \log n)\)?" — draw the tree. When someone asks "why can quicksort be \(O(n^2)\)?" — draw the chain. When someone asks "why is binary search \(O(\log n)\)?" — draw the path.
The tree shape IS the algorithm's complexity. Once you can draw the tree, you can read the answer.
Try It
The starter code implements binary search on a sorted array of 8 elements.
Predict before running: How many comparisons does it take to find 5? Draw the implicit BST and trace the path. (Answer: 3 comparisons — check 4, check 6, check 5.)
Challenge: What's the maximum number of comparisons for binary search on an array of size \(n = 1000\)? (Answer: \(\lceil \log_2 1000 \rceil = 10\).)
Challenge 2: Add a comparison counter to the merge sort snippet. For \(n = 8\), the total should be close to \(n \log_2 n = 24\). For \(n = 16\), it should be close to \(64\). Verify.
Edge Cases to Watch For
- Already sorted input for quicksort: With "first element" pivot selection, a sorted array produces the worst-case chain. Every partition puts 0 elements on one side and \(n-1\) on the other. Use randomized pivot selection to avoid this.
- All elements identical: Quicksort with naive partitioning degenerates to \(O(n^2)\) because every element equals the pivot. Three-way partitioning (Dutch National Flag) handles this by grouping equal elements together.
- Binary search
midoverflow:(left + right) / 2overflows when both are large positive integers. Useleft + (right - left) / 2instead.
Problems
| Problem | Link | Difficulty |
|---|---|---|
| LC 912 — Sort an Array | leetcode.com/problems/sort-an-array | Medium |
| LC 704 — Binary Search | leetcode.com/problems/binary-search | Easy |
| LC 215 — Kth Largest Element (Quickselect) | leetcode.com/problems/kth-largest-element-in-an-array | Medium |