The idea: a comparison sort is a decision tree

Merge sort, heap sort, quicksort and insertion sort all learn about the keys in one way only: they ask "is x < y?" and get yes or no. Fix the number of keys n. Then every run of the algorithm is a path in a binary tree, the decision tree. Each inner node is one compare, its two edges are the two answers, and each leaf is the order the algorithm finally outputs.

Insertion sort's decision tree for 3 keys a, b, c. The root asks a < b. Each inner node asks one compare and has a yes edge and a no edge. The 6 leaves are the 6 orders a<b<c, a<c<b, c<a<b, b<a<c, b<c<a, c<b<a. Two leaves are at depth 2, four at depth 3.
Every leaf is one of the 3! = 6 orders; the longest root-to-leaf path, 3 compares, is the worst case.

The canvas draws the tree of insertion sort on 3 keys a, b, c. Pick an input and press Sort by Comparisons: each question lights up, its answer takes one edge, and the leaves under the other edge turn grey. (Demo: sorted input needs only 2 compares, Demo: a worst-case input needs 3 compares)

n! leaves need height log₂ n!

A correct sort must give a different output for each of the n! orders of the input. Two orders that end in the same leaf would get the same rearrangement, and one of them would come out wrong. So the tree has at least n! leaves.

A binary tree of height h has at most 2h leaves. So 2h ≥ n!, which means h ≥ log₂ n!. The height is the number of compares on the longest path, that is, the worst case. For 3 keys: 6 leaves, so at least ⌈log₂ 6⌉ = 3 compares.

nn! orders⌈log₂ n!⌉ (fewest worst-case compares)merge sort, worst case
3633
42455
512078
103,628,8002225
202.4 × 10186269

(Demo: n! leaves grow like n log n)

The adversary argument

The same bound has a game form. An adversary does not pick the input in advance. When the algorithm asks a question, the adversary looks at the orders that are still possible and answers so that the larger group survives. Each answer can then at best cut the possible orders in half, so it takes at least log₂ n! answers to get down to one. At the end the adversary names an input that fits every answer it gave, so the run was real. On the canvas: 6 → 3 → 2 → 1, three compares. (Demo: the adversary forces 3 compares)

log₂ n! is about n log₂ n

log₂ n! = log₂ 1 + log₂ 2 + … + log₂ n. Half of those terms are at least log₂(n/2), so the sum is at least (n/2) log₂(n/2). Stirling's formula gives the sharp form: log₂ n! ≈ n log₂ n − 1.44 n. So every comparison sort needs Ω(n log n) compares in the worst case (and on average too). Merge sort and heap sort reach O(n log n), so they are optimal up to a constant factor.

Bar chart for n = 4, 8, 12, 16: the lower bound ceil(log2 n!) is 5, 16, 29, 45; merge sort's worst case is 5, 17, 33, 49; n log2 n is 8, 24, 43, 64.
Merge sort's worst case sits just above the bound ⌈log₂ n!⌉; both stay under n log₂ n.

Why counting sort and radix sort can beat it

The bound is about algorithms whose only access to the keys is a compare. Counting sort does something else: it uses a key as an array index. Key 7 goes straight to count[7], with no question about the other keys. One step can then have k outcomes instead of 2, so the decision-tree argument says nothing. For n integers in the range 0..k−1 it runs in O(n + k). Radix sort repeats a counting pass once per digit, O(d·(n + b)) for d digits in base b. The price is an assumption about the keys: small integers or fixed-length digit strings. (Demo: counting sort uses 0 compares)

Left: a compare node a < b has two outcomes, yes and no, so h compares reach at most 2 to the h leaves. Right: counting sort reads key 7 and jumps to slot 7 of count[0..9], one step with 10 possible outcomes.
A compare splits the possibilities in two; an index lookup splits them k ways, which is how counting sort gets under n log n.

See also Comparison Sorting for the sorts this bound applies to, Quick Sort vs Merge Sort for two O(n log n) sorts side by side, and Sorting Networks, where the compares are fixed in advance.

What the page leaves out

The page draws only n = 3 and only insertion sort's tree. It leaves out the average-case bound (the average leaf depth is also at least log₂ n!), Ford–Johnson merge insertion, which needs fewer compares than merge sort and meets the bound for small n, the cases where the bound is not reached (n = 12 needs 30, not 29), lower bounds for related problems such as element distinctness in algebraic decision trees, and integer sorts faster than O(n log n) on the word RAM.