A prefix-free code corresponds to a binary tree where each leaf represents a character of the alphabet. The code word for each character is determined by the character's access path, with left child corresponding to 0, and right child corresponding to 1.
* *
/ \ 0/ \ 1
0/ \1 / \
/ \ [] *
* * a 0/ \1
0 / \1 0/ \1 / \
/ \ / \ [] *
[] [] [] [] b 0/ \1
a b c d / \
[] []
c d
T1 T2
Example. In \(abacad\), \(a\) occurs 3 times, each of \(b, c, d\) occurs once. \(T_1\) gives encoding length \((3 \times 2) + 2 + 2 + 2 = 12\), \(T_2\) gives encoding length \((3 \times 1) + 2 + 3 + 3 = 11\).
Example 2: Here are 2 ways to merge 3 files of length 10, 20, 30:
* *
/ \ / \
/ \ / \
* 30 10 *
/ \ / \
/ \ / \
10 20 20 30
P1 P2
In P2, 1st merge takes time 50, 2nd merge takes time 60, total merge time 110
Proof Sketch.
Consider a binary tree \(T\) with leaves \(L\) and weight \(w(\ell)\), where \(\ell \in L\).
Interpreting \(T\) as a merge tree, define the weight of an interior node to be the sum of the weights of its children. (The weight of an interior node is the time for the merge at that node.)
claim: w.e.p.l. equals the total interior node weight (i.e., total merge time) since a leaf \(\ell\) contributes \(d(\ell)w(\ell)\) to both quantities.
The lemma follows from the claim.
Proof Sketch.
Consider any binary tree whose leaves are the items. Suppose the 2 smallest items aren't siblings of maximum depth. Swap them into that position. The swap doesn't increase the w.e.p.l. So if we start with an optimum tree, we'll get another optimum tree that satisfies the Lemma.
To complete the proof of correctness, we must show that after Huffman algorithm combines the 2 smallest items, it can proceed recursively.
Proof. The first merge of it is valid, by Lemma 1. After the first merge, the problem is to find another optimum merge pattern, so the same strategy works!
So Huffman algorithm is correct.
High-level algorithm
let a and b be 2 items of smallest weight;
replace them by an item p of weight w(a)+w(b);
recursively find the minimum tree R for the new items;
return T the tree R with a and b as children of p;
Let's be given six items with weights 2, 3, 3, 4, 6, 12.
[MISSING FIGURE HERE]
Huffman low-level algorithm:
Q ← empty priority queue
for i ← 1 to n do INSERT item i in Q
for i ← 1 to n-1 do {
a ← EXTRACT_MIN(Q)
b ← EXTRACT_MIN(Q)
combine a & b into a new item & INSERT it in Q
}
/* now Q contains 1 item, representing the Huffman tree */
Total time = \(O(n) \times O(\log n)= O(n \log n)\) since each iteration does \(O(1)\) priority queue operations and each priority queue operation takes \(O(\log n)\) time.