Divide-and-Conquer | Partition-based Recursive Sort
Picture sorting a messy stack of graded exams by score. You grab one paper — call it the pivot — and make two piles: everyone who scored lower goes left, everyone higher goes right. That one paper is now sitting in its exact final rank, and you never touch it again. Then you play the same game on the left pile and the right pile, and on the piles inside those, until every pile is a single paper. The stack is sorted. That splitting move is the whole algorithm.
The single move that does all the work is the partition: walk through the group once, tossing each item to the correct side of the pivot. For a group of $n$ items that takes about $n-1$ comparisons — just one pass. If the pivot lands near the middle each time, the group roughly halves every round, so it takes about $\log_2 n$ rounds to shrink everything to singletons. One pass per round times $\log_2 n$ rounds gives roughly $n\log_2 n$ comparisons of work. For $n=16$ that is about $16\times4=64$ comparisons, versus $16^2=256$ for a clumsy compare-everything sort — already 4× cheaper, and the gap widens fast as $n$ grows.
The average-case recurrence writes this down precisely: $T(n)=2T(n/2)+(n-1)$, which the Master Theorem (Case 2) closes to $\Theta(n\log n)$. But quicksort's speed is hostage to the pivot. A balanced split gives that happy $\log_2 n$ depth; a terrible pivot — always the largest or smallest element — peels off just one item per round, so $T(n)=T(n-1)+(n-1)=\tfrac{n(n-1)}{2}=\Theta(n^2)$. That is the worst case the simulation reproduces when you feed it sorted data with a last-element pivot. The cure is to choose the pivot well: a random pivot or median-of-3 makes the bad case astronomically unlikely. In the panel above, the Pivot Strategy menu and the Preset selector map straight onto this — the pivot choice is the single variable that swings the entire runtime between $n\log n$ and $n^2$.
| Symbol | Meaning |
|---|---|
| n | Number of elements |
| T(n) | Comparisons for array of size n |
| p | Partition index (0-indexed) |
| T(k) | Left subproblem of size k |
| T(n−k−1) | Right subproblem |
| I(n) | Inversions count |
❌ "Quicksort is always faster than Mergesort."
✅ Quicksort is faster on average with cache-friendly data, but Mergesort has guaranteed O(n log n) and is faster for linked lists or external sorting.
❌ "Pivot is always placed at the center after partition."
✅ Pivot ends up at its correct sorted position, which could be anywhere from index 0 to n−1 depending on input.
❌ "Quicksort is stable."
✅ Standard Quicksort is NOT stable. Equal elements can change relative order. Use Mergesort or TimSort if stability is required.
❌ Using lo + (hi-lo)/2 as pivot is equivalent to picking the median.
✅ That picks the middle-index element, not the median value. Median-of-3 requires comparing values, not just averaging indices.
❌ Always using i < j in Lomuto partition (should be j < hi).
✅ In Lomuto scheme, j runs from lo to hi−1. The condition is j < hi (not j <= hi, which would include the pivot in comparisons).
❌ Forgetting base case: calling QUICKSORT(A, lo, lo) unnecessarily.
✅ The base case is lo < hi (strictly less). A single element (lo == hi) or empty range (lo > hi) must immediately return without partitioning.