Randomized Quick Sort
Imagine you need to sort 100 people by height. You pick someone from the group to be the referee. Everyone shorter stands to their left, everyone taller stands to their right. Then you do the same thing recursively for each half.
If the referee happens to be near the middle height-wise, each half has about 50 people — and the work halves nicely at each step: \(O(n \log n)\) total. But if you always pick the tallest person as referee, one side has 99 people and the other has 0 — degenerate \(O(n^2)\) behavior.
The fix is simple: pick the referee randomly. A random person is unlikely to be the very tallest or shortest. And even if one unlucky pick happens, the next level of recursion gets a new random choice — the chances of every single pick being terrible shrink exponentially.
Why Deterministic QuickSort Fails on Sorted Input
The classic bug in deterministic QuickSort: pick the last element as pivot every time. On an already-sorted array like [1, 2, 3, 4, 5], the last element is always the maximum. Every partition is maximally unbalanced: one side has 0 elements, the other has n-1. You get n recursion levels, each doing \(O(n)\) work — quadratic total.
This isn't just a theoretical problem. Sorting a sorted or nearly-sorted list is a very common real-world operation. Many systems feed sorted data into QuickSort and wonder why it crawls.
Random Pivot: No Input Can Be Adversarial
With a random pivot, no fixed input causes worst-case behavior. To force \(O(n^2)\), the adversary would need to predict your random choices at every single level of recursion — which they can't do. The worst case becomes a function of your random number generator, not the data.
The Expected Comparisons Analysis
Define X_{ij} = 1 if elements with sorted ranks i and j are ever directly compared. Two elements are compared only when one of them is the pivot while both are in the same subarray. The probability of this? Exactly 2 / (j − i + 1) — there are j-i+1 elements between them in sorted order, and the comparison happens only if i or j is picked first as pivot.
Summing over all pairs: E[comparisons] = Σ 2/(j-i+1) ≈ 2n·ln(n) = \(O(n \log n)\). This holds for every possible input.
Introsort: The Best of Both Worlds
Real-world sort implementations (C++ std::sort, Rust's sort_unstable) use introsort: start with randomized QuickSort but monitor recursion depth. If depth exceeds 2·log n — a sign of consistently bad pivots — switch to HeapSort, which guarantees \(O(n \log n)\) worst case. This combines QuickSort's excellent cache performance with an absolute worst-case guarantee. Randomized QuickSort is a classic Las Vegas algorithm — always correct, only runtime varies.