DSA Notes
Master Huffman coding completely — what prefix-free codes are, why Huffman coding is optimal, building the Huffman tree with a priority queue, encoding and decoding, calculating compression ratio, and applications in ZIP, JPEG, and MP3 compression.
What Is Huffman Coding?
Huffman coding is a lossless data compression algorithm that assigns variable-length binary codes to characters based on their frequencies — common characters get shorter codes, rare characters get longer codes.
Example: In English text, 'e' appears ~12.7% of the time while 'z' appears ~0.07%. Huffman gives 'e' a short code (like 01) and 'z' a long code (like 1011011).
Building the Huffman Tree
Algorithm:
- Create a leaf node for each character with its frequency
- Insert all nodes into a min-heap (by frequency)
- While heap has more than one node:
a. Extract two minimum-frequency nodes b. Create internal node with frequency = sum of both c. Make the two nodes children d. Insert new internal node back into heap
- The remaining node is the root
Generating Codes
Output for "ABRACADABRA":
| 'A' | 0 (freq=5) ← most common, shortest code |
| 'B' | 100 (freq=2) |
| 'C' | 1010 (freq=1) |
| 'D' | 1011 (freq=1) |
| 'R' | 11 (freq=2) |
| Original | 88 bits (11 chars × 8 bits) |
| Encoded | 23 bits (5×1 + 2×3 + 1×4 + 1×4 + 2×2) |
| Compression ratio | 26.1% of original! |
Decoding
def huffman_decode(encoded_bits, root):
"""
Decode Huffman-encoded binary string using the tree.
"""
decoded = []
current = root
for bit in encoded_bits:
if bit == '0':
current = current.left
else:
current = current.right
if current.char is not None: # Reached leaf
decoded.append(current.char)
current = root # Reset to root for next character
return ''.join(decoded)
root = build_huffman_tree("ABRACADABRA")
encoded, codes = huffman_encode("ABRACADABRA")
decoded = huffman_decode(encoded, root)
print(decoded) # ABRACADABRA ✓Optimality Proof
Theorem: Huffman coding produces an optimal prefix-free binary code — no other prefix-free code achieves fewer expected bits per character.
Proof (key ideas):
- In any optimal code tree, the two rarest symbols must be at the deepest level (otherwise, swap them with deeper nodes to reduce expected length).
- The two rarest symbols must be siblings (adjacent nodes with same parent) in an optimal tree.
- Therefore: combining the two rarest into a "super-symbol" and solving optimally for the reduced set gives the optimal solution for the original set.
This is exactly what Huffman's algorithm does — a greedy reduction step that is provably optimal.
Expected code length:
Compression Ratio Analysis
Real-World Applications
| System | Use of Huffman |
|---|---|
| ZIP/DEFLATE | Huffman within DEFLATE compression algorithm |
| JPEG images | Huffman coding for DCT coefficients |
| MP3 audio | Huffman coding for frequency data |
| HTTP/2 | HPACK header compression uses Huffman |
| Morse code | Inspired Huffman (common letters get shorter codes) |
Summary
Huffman coding:
- Greedy choice: Always merge two lowest-frequency nodes
- Time: O(n log n) — heap operations
- Optimal: Produces minimum expected bits per symbol
- Prefix-free: Allows unambiguous decoding
- Used in: ZIP, JPEG, MP3, HTTP/2
The beauty of Huffman coding is that a simple greedy algorithm (always merge the cheapest pair) produces a provably optimal result.
*Next Lesson: Job Sequencing Problem*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Huffman Coding — Optimal Prefix-Free Data Compression.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, greedy, huffman, coding
Related Data Structures & Algorithms Topics