Huffman coding
Optimal prefix codes: variable-length codes, the prefix property and the Kraft inequality, Huffman's algorithm (repeatedly merge the two least frequent symbols, with a min-heap in O(n log n)), the cost as the sum of the weights of the internal nodes, a worked tree and code table, why the greedy choice is optimal, decoding, tie-breaking, extreme shapes of the tree, and the entropy bounds.
Why it exists
Text, images and files are stored as bit strings. A fixed-length code gives every symbol the same number of bits ( for symbols), which wastes space when some symbols are far more frequent than others (the letter against ). Huffman coding gives frequent symbols short code words and rare ones long ones, in the best possible way: it produces the prefix code with the smallest average length. The algorithm is a textbook greedy algorithm (always merge the two least frequent), its proof is an exchange argument, and its implementation is a heap, so it is where the greedy method and the priority queue meet.
Prerequisites
You need the greedy method and its exchange proofs (greedy method) and the min-heap (binary heap).
Precise definitions
Code and code word. A code assigns to each symbol a string of bits, its code word. A message is encoded by concatenating the code words of its symbols.
Prefix code. No code word is a prefix (beginning) of another. Then the bit string can be decoded from left to right with no separators and no look-ahead: when the bits read so far equal a code word, that symbol is output. A prefix code corresponds to a binary tree whose leaves are the symbols; the code word of a leaf is the path from the root (0 for left, 1 for right).
Cost. For frequencies and code word lengths (the depth of the leaf), the cost is (the number of bits of the encoded message, if counts the occurrences). The average code length is . An optimal code minimises it.
Kraft inequality. A prefix code with code word lengths exists if and only if . It holds with equality exactly for full binary trees (every internal node has two children), and an optimal code is always full.
Entropy. with . No code can have an average length below , and the Huffman code satisfies .
How it works
The algorithm
- Make a node for each symbol, with its frequency as weight.
- While more than one node is left: remove the two nodes of smallest weight, make a new node with them as children (the smaller on the left, say) and the sum of their weights as weight, and insert it back.
- The last node is the root. Read the code words from the root: for left, for right.
With a min-heap each of the merges costs (two extractions and one insertion): total . With a plain sorted array or list it is ; the C program below uses the simple version because it is short, with the same result.
The program runs the algorithm for six symbols with the frequencies , , , , , (per symbols), prints every merge and the forest after it, then the code words.
#include <stdio.h>
#define MAXN 16
static int weight[2 * MAXN], left_[2 * MAXN], right_[2 * MAXN], total_nodes;
static char symbol[2 * MAXN];
static void show(int node) { /* prints a tree as nested parentheses: (left right) */
if (left_[node] < 0) { printf("%c", symbol[node]); return; }
printf("(");
show(left_[node]);
printf(" ");
show(right_[node]);
printf(")");
}
static void assign(int node, char *prefix, int depth, char codes[][MAXN]) {
if (left_[node] < 0) { prefix[depth] = 0; for (int i = 0; i <= depth; i++) codes[symbol[node] - 'A'][i] = prefix[i]; return; }
prefix[depth] = '0'; assign(left_[node], prefix, depth + 1, codes);
prefix[depth] = '1'; assign(right_[node], prefix, depth + 1, codes);
}
int main(void) {
const char *names = "ABCDEF";
int freq[6] = {35, 22, 17, 11, 9, 6};
int live[2 * MAXN], nlive = 6, cost = 0;
for (int i = 0; i < 6; i++) { weight[i] = freq[i]; symbol[i] = names[i]; left_[i] = right_[i] = -1; live[i] = i; }
total_nodes = 6;
for (int step = 1; nlive > 1; step++) {
int lo = 0, lo2 = -1; /* positions in live[] of the smallest and second smallest weight */
for (int i = 1; i < nlive; i++) if (weight[live[i]] < weight[live[lo]]) lo = i;
for (int i = 0; i < nlive; i++) if (i != lo && (lo2 < 0 || weight[live[i]] < weight[live[lo2]])) lo2 = i;
int x = live[lo], y = live[lo2], z = total_nodes++;
weight[z] = weight[x] + weight[y];
left_[z] = x;
right_[z] = y;
cost += weight[z];
printf("step %d: merge ", step); show(x); printf(":%d and ", weight[x]); show(y); printf(":%d -> %d (cost so far %d)\n", weight[y], weight[z], cost);
live[lo] = z; /* the new node replaces the first, the last live node fills the gap */
live[lo2] = live[nlive - 1];
nlive--;
printf(" forest:");
for (int i = 0; i < nlive; i++) { printf(" "); show(live[i]); printf(":%d", weight[live[i]]); }
printf("\n");
}
char codes[6][MAXN], prefix[MAXN];
assign(live[0], prefix, 0, codes);
int bits = 0;
for (int i = 0; i < 6; i++) {
int len = 0;
while (codes[i][len]) len++;
bits += freq[i] * len;
printf("code %c freq %2d %s\n", names[i], freq[i], codes[i]);
}
printf("total bits per 100 symbols: %d (fixed length: %d)\n", bits, 300);
return 0;
}step 1: merge F:6 and E:9 -> 15 (cost so far 15)
forest: A:35 B:22 C:17 D:11 (F E):15
step 2: merge D:11 and (F E):15 -> 26 (cost so far 41)
forest: A:35 B:22 C:17 (D (F E)):26
step 3: merge C:17 and B:22 -> 39 (cost so far 80)
forest: A:35 (D (F E)):26 (C B):39
step 4: merge (D (F E)):26 and A:35 -> 61 (cost so far 141)
forest: (C B):39 ((D (F E)) A):61
step 5: merge (C B):39 and ((D (F E)) A):61 -> 100 (cost so far 241)
forest: ((C B) ((D (F E)) A)):100
code A freq 35 11
code B freq 22 01
code C freq 17 00
code D freq 11 100
code E freq 9 1011
code F freq 6 1010
total bits per 100 symbols: 241 (fixed length: 300)Huffman's algorithm on frequencies 35, 22, 17, 11, 9, 6: start
Computed by a script, not typed| step | the two smallest nodes (tree:weight) | new weight | forest after the merge (tree:weight) | sum of new weights so far |
|---|---|---|---|---|
| step 1 | ||||
| step 2 | ||||
| step 3 | ||||
| step 4 | ||||
| step 5 |
Step 0
Six symbols A to F with frequencies 35, 22, 17, 11, 9, 6 (per 100 symbols). Repeatedly the two nodes of smallest weight are replaced by one node whose weight is their sum, until one tree is left.
The two smallest at first are and , merged into ; then with that gives ; and give ; and give ; at last and give the root, . The final tree (in nested notation) is .
The Huffman code: start
Computed by a script, not typed| symbol | frequency | code word | length | frequency x length |
|---|---|---|---|---|
| A | ||||
| B | ||||
| C | ||||
| D | ||||
| E | ||||
| F |
Step 0
Reading the tree from the root: 0 for the left branch (the smaller subtree) and 1 for the right. No code word is the beginning of another, so a bit string decodes in only one way. Total 241 bits per 100 symbols, against 300 for a fixed 3-bit code.
Reading the tree: , , , , , . The frequent symbols have two bits, the rare ones four.
The cost without the code words. Each merge creates one internal node whose weight is the sum of the frequencies below it; a symbol at depth is counted in internal nodes (all its ancestors). So Here : 241 bits per 100 symbols, an average of bits, against (3 bits each) for a fixed-length code, a saving of . (The merge table shows this running sum.)
Decoding. Read bits until they equal a code word: is = . Because no code word is a prefix of another, the first match is the only possible one.
Why it is optimal
Greedy choice. Let and be the two least frequent symbols. In an optimal tree the deepest leaves are the least frequent symbols (otherwise swapping a deeper, more frequent symbol with a shallower, less frequent one lowers the cost: an exchange argument), and the deepest level contains two sibling leaves (an optimal tree is full). So there is an optimal tree in which and are siblings at the deepest level: merging them first loses nothing.
Optimal substructure. Replace and by one symbol of frequency . The cost of a tree for the original symbols equals the cost of the corresponding tree for the smaller alphabet plus (the extra depth of the two leaves). So an optimal tree for the original problem comes from an optimal tree for the smaller problem; by induction on , Huffman's algorithm is optimal.
The result was also tested exhaustively: for random frequency sets the Huffman cost equalled the minimum over all code length assignments that form a complete prefix code.
Properties and shapes
- The code is not unique. Ties between equal weights, and the choice of which child is , give different trees; all have the same cost (the minimum) but possibly different code word lengths.
- Number of nodes. leaves and internal nodes (a full binary tree), so merges.
- Equal frequencies, : every code word has bits: Huffman gives the fixed-length code. For other with equal frequencies the lengths are or .
- Most skewed tree: the Fibonacci frequencies give a chain: the rarest symbols get codes of bits.
- Entropy: the average length satisfies . For frequencies that are all powers of (such as ) it equals exactly.
- Assumptions: it is optimal among codes that give each symbol a separate code word, for a known, fixed frequency table (which must also be stored or transmitted); adaptive and block-based codes can do better.
Worked examples
EX 1Build a Huffman tree
EasyFrequencies , , , . Merge . Nodes: , , . Merge . Nodes: , . Merge . The cost is the sum of the new weights: . Check with the depths: the tree is , all four leaves have depth , so the cost is ✓. Codes: , , , : the same as the fixed-length code, because the frequencies are close together.
EX 2Compare with a fixed-length code
EasyFor the table of this page ( symbols) a fixed-length code needs bits per symbol: bits per symbols. Huffman needs . A message of symbols with these frequencies takes about bits instead of .
EX 3Which sets of lengths can be a prefix code?
MediumKraft: lengths : : a complete prefix code exists (). Lengths : : no prefix code has these lengths. Lengths : sum : a prefix code exists but it is not complete, so it is not optimal (a length can be shortened).
EX 4Cost from the merge weights
MediumFrequencies . Merge ; nodes : merge ; nodes : merge (either pair of equal s, same cost); nodes : merge . Cost . Check with depths: the symbols with frequency and and get lengths and the two rarest get : ✓. This is the chain shape: depth .
EX 5Typical questions
GATE level(a) Number of merges for symbols: ; time with a heap: . (b) For frequencies how many bits does the longest code word have? Five equal frequencies: lengths are or , so the longest has bits. (c) Is a prefix code? No: is a prefix of and of . (d) Does every set of frequencies have a unique Huffman code? No: ties and the labelling of branches give several codes, all with the same minimum cost. (e) If all symbols have frequencies that are powers of two (): lengths and the average length equals the entropy ( bits).
Cheat box
Cheat box
- Prefix code: no code word is a prefix of another; leaves of a binary tree; decodable left to right.
- Cost sum of the weights of the internal nodes. Fixed-length: bits.
- Huffman: repeatedly merge the two least frequent; merges; with a min-heap .
- Optimal by exchange: the two rarest symbols can be sibling leaves at the deepest level.
- Not unique (ties, labelling), but the cost is. Kraft: (equality for full trees).
- Entropy . Equal frequencies, : all lengths . Fibonacci frequencies: a chain.
Traps and GATE patterns
Connections
Huffman's algorithm is a greedy algorithm (greedy method) that uses a min-heap (binary heap, heap applications). Like activity selection and fractional knapsack its proof is an exchange argument.
PYQs
5 previous year questions from your book. I re-solved each one myself (5 by running or simulating, 0 by reasoning only); the book's key is shown next to my answer. All PYQs
Consider the string abbccddeee. Each letter in the string must be assigned a binary code satisfying the following properties: For any two letters, the code assigned to one letter must not be a prefix of the code assigned to the other letter. For any two letters of the same frequency, the letter which occurs earlier in the dictionary order is assigned a code whose length is at most the length of the code assigned to the other letter. Among the set of all binary code assignments which satisfy the above two properties, what is the minimum length of the encoded string?
- (a)21
- (b)23
- (c)25
- (d)30
A message is made up entirely of characters from
the set X = {P,Q,R,S,T} . The table of
probabilities of each character is shown below :
Character
Probability
P
0.22
Q
0.17
R
0.34
S
0.19
T
0.08
Total
1.00
A message of 100 characters over X is encoded
using Huffman coding. Then the excepted length
of the encoded message in bits isSuppose the letters a, b, c, d, e, f have probabilities 1/2, 1/4, 1/8, 1/16, 1/32, 1/32 respectively. What is the average length of the Huffman code for the letters a,b,c,d,e,f?
- (a)3
- (b)2.1875
- (c)2.25
- (d)1.9375
Suppose the letters a, b, c, d, e, f have probabilities 1/2, 1/4, 1/8, 1/16, 1/32, 1/32 respectively. Which of the following is the Huffman code for the letter a, b, c, d, e, f?
- (a)0, 10, 110, 1110, 11110, 11111
- (b)11, 10, 011, 010, 001, 000
- (c)11, 10, 01, 001, 0001, 0000
- (d)110, 100, 010, 000, 001, 111 ALGORITHMS Check Out Our Gate Courses & Secure Your Dream Rank !
The characters a to h have the set of frequencies based on the first 8 Fibonacci numbers as follows a:1, b:1, c:2, d:3, e:5, f:8, g:13, h:21 A Huffman code is used to represent the characters. What is the sequence of characters corresponding to the following code? 110111100111010
- (a)fdheg
- (b)ecgdf
- (c)dchfg
- (d)fehdg
Self-check
Question 1
Frequencies . What is the cost of the Huffman code (total bits)?
Show answerHide
Merge ; nodes : ; nodes : ; nodes : ; nodes : . Cost .
Question 2
Can a prefix code have code word lengths ?
Show answerHide
No: (Kraft). After using and no longer code word is available.
Question 3
What is the running time of Huffman's algorithm with a min-heap for symbols?
Show answerHide
: merges, each .
Question 4
Why are the two rarest symbols sibling leaves at the deepest level in some optimal tree?
Show answerHide
A more frequent symbol deeper than a rarer one can be swapped with it, lowering the cost; and an optimal tree is full, so the deepest level has two sibling leaves.
Revision card
One-screen revision
- Prefix code = leaves of a binary tree; cost = sum of internal node weights.
- Huffman: merge the two smallest repeatedly; merges; heap ; optimal (exchange + substructure).
- Kraft ; .
- Not unique, cost unique. Equal frequencies : bits each; Fibonacci: chain.
References
- ·Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (3rd edition), Section 16.3 Huffman codes
- ·Kleinberg and Tardos, Algorithm Design, Section 4.8 Huffman codes and data compression
- ·Sedgewick and Wayne, Algorithms (4th edition), Section 5.5 Data compression (Huffman compression)
Verification
The Huffman cost was compared with the minimum over EVERY assignment of code lengths that forms a complete prefix code (Kraft sum equal to one), for 150 random frequency sets of up to 6 symbols: always equal, and equal under two different tie-breaking rules. The Kraft inequality was checked in both directions (code words can be constructed when the sum is at most 1; for small cases no prefix code exists when it exceeds 1). The entropy bounds H <= average length < H + 1 held on 300 random frequency sets. The page example (frequencies 35, 22, 17, 11, 9, 6: cost 241 against 300 for a 3-bit code) was produced by the C program on this page, whose tree and codes were recomputed in Python; random strings decode uniquely with the code. The shapes (Fibonacci frequencies give a chain, equal frequencies give balanced codes) were confirmed for n up to 9. Textbook references are from memory. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (loop counts, recurrences, merge and quicksort counts and averages, hash probes and load-factor formulas, DP tables, MST and shortest-path runs, Floyd matrices); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose); tables and animations are machine output and were read, not re-run; No other defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)