Algorithms & Data Structures • Sensei Learning System
The cleanest “you cannot do better than this” proof in all of algorithms — one decision tree, one factorial, and you’re done.
A comparison sort learns about the input only by asking pairwise questions — “is a less than b?” — and never looks inside the keys. Model any deterministic comparison sort as a binary decision tree: every question is a branch, every complete run ends at a leaf holding the discovered order.
There are n! possible orders of n distinct keys, so the tree needs at least n! leaves — and a binary tree of height h has at most 2h leaves. That single fact forces the bound:
No comparison sort — no matter how clever — can guarantee worst-case Ω(n log n) comparisons. This is not a limitation of known algorithms; it is a law of the model.
Each internal node is one comparison “a < b?”, each branch a yes/no answer, each leaf a fully determined input order.
Every one of the n! permutations must end at its own leaf: two inputs reaching the same leaf got identical answers, so they’d be sorted identically — impossible.
log₂(n!) = n log₂ n − 1.44n + O(log n), so ⌈log₂(n!)⌉ grows like n log n. The factorial becomes the bound.
Merge sort and heapsort hit O(n log n) worst-case — the bound is tight. Quicksort averages O(n log n) but degrades to O(n²) with bad pivots.
Four distinct keys can arrive in 4! = 24 orders. A 4-level tree holds only 2⁴ = 16 leaves — not enough. So some input forces at least ⌈log₂ 24⌉ = 5 comparisons. No sorting trick escapes it.
This is a lower bound on comparison-based sorting, not on sorting in general. The model’s only information source is “a < b?” — and that constraint is exactly what non-comparison sorts dodge.
Counting sort (keys in 0…k) and radix sort use the keys’ structure — bucket indexing, digit-by-digit passes — to place items without asking pairwise questions. They run in roughly linear time (O(n + k), O(d·n)) for bounded/structured keys. That does not disprove the bound: it changes the model by adding an operation the comparison sort is not allowed.
Standard library sorts. C’s qsort, Python’s Timsort, Java’s Arrays.sort — all comparison sorts. The bound is the ceiling: O(n log n) is “as good as it gets” for arbitrary keys, which is why nobody hunts for a faster general-purpose one.
Database ORDER BY and index builds. Sorting arbitrary values (strings, timestamps, composite keys) is comparison sorting; the bound sets the expected cost you’re paying when a query files away a large result set.
Picking counting/radix sorts. When keys are bounded integers — byte arrays, fixed-width IDs, scores 0–100 — you can legally leave the comparison model and get linear-ish time. Recognizing when you may is the real skill the bound teaches.
Lower-bound thinking in general. Proving an algorithm cannot be faster is worth as much as finding a fast one — it stops whole search programs (e.g. “faster than n log n general sorting?”) before they start.