The tree makes frequent symbols cheaper.
Weighted leaves form a binary code tree where frequent symbols receive shorter paths, and the same representation drives both encoding and decoding.
How can one weighted tree determine both the bits we write and the symbols we recover?
- Represent each leaf with one symbol and its frequency weight
- Build a code tree by repeatedly merging the two lightest nodes
- Encode a symbol by following branch membership from the root
- Decode bits by walking to a leaf and restarting at the root
make-leaf-set orders the finite weighted symbols from lightest to heaviest. successive-merge removes the two lightest nodes, combines their symbol sets and weights, and inserts the new node back into that order until one tree remains. With the shipped weights, A receives a one-bit path while B, C, and D receive progressively deeper paths.
Encoding asks whether the next symbol belongs to the left or right branch and records 0 or 1 before continuing below that branch. Decoding consumes the same decisions in the opposite direction. Reaching a leaf emits its symbol and returns to the root for the next code word. Equal weights can admit another valid tree; the explicit insertion rule fixes the tree used by these runs.
- Output
- —
- Value
- —
- Diagnostic
- —
The first program returns (8 (A B C D) ((0) (1 0) (1 1 0) (1 1 1))). The second returns ((0 1 1 1 1 0) (A D B)).
Follow the weighted merges that make the root, then compare each symbol-membership test with the emitted branch bit. During decoding, watch the same bits choose branches until a leaf emits a symbol and the walk restarts at the root. The execution trace records this tree and message under fixed runtime limits.
Change the program and compare the result.
Encode (A B C D A) with the shipped tree. Before running it, predict the total bit count and explain why A contributes fewer bits than C or D.
Show hint
Read each code from the first example, concatenate the five paths, and count their branch decisions.