Definition · The coding problemGiven symbols with positive integer weights, assign each a binary codeword so that no codeword is a prefix of another, minimising the total Σ wᵢ · |cᵢ| — the number of bits needed to write a text in which each symbol appears with its weight as a count. Dividing that total by Σ wᵢ gives the expected codeword length.
Definition · Huffman's algorithmPut every symbol in a collection as a single-node tree with its weight. Repeatedly remove the two lightest trees, join them under a new node whose weight is their sum, and put that node back. After n - 1 merges one tree remains; label left edges 0 and right edges 1, and each leaf's root-to-leaf path is its codeword.
The greedy commitment is the merge. Once two trees have been joined, the symbols beneath them stay at the same depth relative to each other forever, and nothing later reconsiders it. What makes this an unusual greedy algorithm is the direction: the choice is made at the leaves, where the rarest symbols are, and the consequence — the codewords — is read off at the end.
Example · Six symbols, five mergesThe lab opens on a:45, b:13, c:12, d:16, e:9, f:5. The merges are f + e = 14, then c + b = 25, then 14 + d = 30, then 25 + 30 = 55, then a + 55 = 100. The codewords come out a = 0, c = 100, b = 101, f = 1100, e = 1101, d = 111, with lengths 1, 3, 3, 4, 4 and 3. Total bits 224, total weight 100, expected length 56/25.
The heaviest symbol got the shortest codeword and the two lightest got the longest, which is the whole idea, and it is worth checking against the alternative: a fixed-length code over six symbols needs 3 bits each, so it spends 300 bits on the same text. The saving is 19/25 of a bit per symbol, which the panel prints as a fraction as well.
The saving is a fact about the distribution, not about the algorithm
Run the same algorithm on four equal weights, a:10, b:10, c:10, d:10. Every codeword comes out two bits, the expected length is exactly 2, a fixed-length code over four symbols is also 2, and the saving is 0. Huffman did nothing wrong; there was nothing to do. A reader who has only ever seen the skewed example carries away “Huffman compresses” as a property of the algorithm, and it is a property of the input.
The other direction is on the panel too. On a:60, b:20, c:10, d:5, e:5 the common symbol gets one bit and the two rarest get four, and the expected length falls to 17/10 against a fixed-length cost of 3. Same algorithm, three different distributions, savings of 19/25, 13/10 and 0.
Where a preset's caption is wrong
The Fibonacci-weight instance, a:1, b:1, c:2, d:3, e:5, produces the deepest tree five leaves can have: depths 4, 4, 3, 2, 1, so the tree is a path and the rarest symbols need four bits. Both of those are true and the panel prints them. The caption's reason is not: it says each merge is exactly the next weight, and the merged weights are 2, 4, 7, 12 against symbol weights 1, 1, 2, 3, 5. Only the first merge matches. After 1 + 1 = 2 the collection holds two twos, and the next merge takes both of them rather than the two and the three.
Theorem · Kraft's equality for a Huffman codeFor a code produced by this algorithm on n symbols with codeword lengths ℓ₁, …, ℓₙ, the sum Σ 2^(−ℓᵢ) equals exactly 1.
A prefix code can only ever satisfy Σ 2^(−ℓᵢ) ≤ 1 — each codeword of length ℓ rules out a 2^(−ℓ) share of the space of infinite bit strings, and the shares are disjoint. Equality means nothing is left over: every bit string has a prefix that is a codeword. Huffman achieves equality because the tree it builds is full, every internal node having two children, and a full tree leaves no unused branch.
That gives a quick sanity check by hand. On the opening code the lengths are 1, 3, 3, 4, 4, 3 and the sum is 1/2 + 1/8 + 1/8 + 1/16 + 1/16 + 1/8, which is 1. On the equal-weight code four lengths of 2 give 4 · 1/4 = 1. A code whose lengths sum to less than 1 has a branch going nowhere and can be shortened; one that sums to more than 1 is not a prefix code at all.
The three checks, and what each one would catch
codesPrefixFree compares every pair of codewords, so a code that happened to be built wrongly would be caught even though the tree construction guarantees it. encodeSyms and decodeBits run the message out and back, and the panel prints the decoded text. And the decoder refuses rather than guesses: append a proper prefix of the longest codeword to a valid bit stream and it returns nothing, because the leftover bits cannot be spent.
Measured on this page: on the six-symbol alphabet, 224 bits over weight 100, expected length 56/25, saving 19/25, prefix-free confirmed pairwise, and abcdef encoded to 18 bits and decoded back unchanged. Proved on this page: Kraft's sum is exactly 1 for any code this algorithm produces. What is not on this page is the claim that no code is shorter, and that is the next thing to establish rather than something the fraction above implies.