Mastering Variable Length Coding
Huffman Coding
What is Huffman Coding?
Huffman coding is a specific method for creating an optimal set of variable-length codes for a given piece of data. As you've learned, variable-length coding saves space by giving shorter codes to symbols that appear frequently. Huffman's algorithm provides a clear, step-by-step way to generate the most efficient codes possible for this task.
The key to its success is the creation of prefix codes. This simply means that no code for a symbol is the beginning of another symbol's code. For instance, if 'A' is 01, no other symbol can have a code like 010 or 0110. This rule is crucial because it eliminates ambiguity, allowing us to decode a stream of bits without needing special separators between codes.
Building the Huffman Tree
The entire process revolves around building a special binary tree, known as a Huffman tree. This tree organises the symbols based on their frequency, ensuring that the most common characters end up with the shortest paths from the root, which translate into the shortest codes.
Let's walk through an example. Imagine we want to compress the string: ABCCCDDDDEEEEE.
- Count Frequencies: First, we count how many times each character appears. A: 1 B: 1 C: 3 D: 4 E: 5
-
Create Leaf Nodes: We treat each character and its frequency as a separate leaf node. Think of it as a small forest of individual nodes.
-
Combine the Smallest: Find the two nodes with the lowest frequencies and combine them. Create a new parent node whose frequency is the sum of its children. In our case, 'A' (1) and 'B' (1) are the lowest. We join them under a new node with a combined frequency of 2. 'A' and 'B' are no longer considered on their own.
-
Repeat: We repeat this process, always combining the two nodes with the lowest frequencies. This might involve combining two original leaf nodes, a leaf and a combined node, or two combined nodes. This continues until only one node remains: the root of the tree.
Encoding and Decoding
Once the tree is built, generating the codes is straightforward. We start at the root and traverse down to each character's leaf node. We assign a 0 to every left branch and a 1 to every right branch (or vice versa, as long as it's consistent). The sequence of 0s and 1s along the path from the root to a leaf becomes that character's code.
| Character | Frequency | Path from Root | Code |
|---|---|---|---|
| E | 5 | Left | 0 |
| D | 4 | Right, Left | 10 |
| C | 3 | Right, Right, Left | 110 |
| A | 1 | Right, Right, Right, Left | 1110 |
| B | 1 | Right, Right, Right, Right | 1111 |
Notice how 'E', the most frequent character, gets the shortest code (0), while 'A' and 'B', the least frequent, get the longest codes. This is the core principle of Huffman coding in action.
To encode our original string ABCCCDDDDEEEEE, we just replace each character with its new code:
1110 1111 110 110 110 10 10 10 10 0 0 0 0 0
Decoding is just as simple. To decode a bitstream, you start at the root of the same Huffman tree. You read one bit at a time from the encoded data, moving left for a 0 and right for a 1. When you reach a leaf node, you've identified a character. You record that character and then return to the root to start the process over with the next bit.
Because it's a prefix code, there's never any confusion. When you reach a leaf, you know that a complete code has been read. You can't accidentally continue and form part of another, longer code.
Applications
Huffman coding is a form of lossless compression, meaning no data is lost in the process; the original data can be perfectly reconstructed. Its efficiency and simplicity have made it a component in many well-known compression formats.
It is often used as a final step in a multi-stage compression process. For example, in ZIP files, after a different algorithm (like DEFLATE) finds and replaces repeated strings, Huffman coding is used to compress the resulting symbols. In JPEG image compression, it's used to compress the values that represent colour and brightness information after they have been transformed and quantised.
Its role as a fundamental building block in data compression highlights its importance in making our digital files smaller and faster to transmit.
What is the defining characteristic of a prefix code, which is essential to how Huffman coding works?
During the construction of a Huffman tree, which two nodes are selected to be combined at each step of the algorithm?