信源编码:频繁符号为什么要短码
WARNING
🧪 Beta公测版本提示:教程主体已完成,正在优化细节,欢迎大家提Issue反馈问题或建议。
无噪声时,压缩的极限是熵:平均码长
。Huffman 是一种前缀码,把概率大的符号放在短分支上。容量与噪声留给 香农 和 信道编码;允许主动失真见 率失真。
正文先讲前缀与 Kraft;需要把
一、前缀码与 Kraft
前缀码:没有任何码字是另一个码字的前缀,才能即时解码(不必等结束符)。平均长度
等号在
保姆级:为什么「前缀」这么重要。 电文是 0/1 连在一起写的,没有逗号。若 A=0、B=01,看见 0 你不知道是已经结束的 A,还是 B 的开头。若任何码字都不是别的码字的前缀(A=0、B=10、C=110、D=111),译码器可以贪心往下吃:走到叶子就输出一个符号。这叫即时可解。

图解说明:概率大的叶子离根近;平均码长
贴在熵 上方。这是可变长度,不是固定 。
逐步推导:Kraft 不等式怎样逼出 (点击展开)
对进制
直觉:把无穷二叉树的节点看成区间,前缀码的叶子区间不相交,总长度不能超过
熵与码长的差可以写成 KL。令
因为 KL
固定长度编码每个符号
二、Huffman 怎么长树
反复把当前最轻的两棵子树合并,左
逐步推导:对 Huffman 怎样长出码本(点击展开)
与 demo.py 的堆实现一致(先弹出更轻的,左标 0、右标 1):
- 最轻两片叶子
与 合并成 。暂定 、 (相对这个新节点)。 - 现在袋里是
、 、 。再合并 与 得 : , 。 - 最后
与 合并: ,另一侧 。
从根往叶子读:
| 符号 | 码 | 长度 |
|---|---|---|
| A | 0 | 1 |
| B | 10 | 2 |
| D | 110 | 3 |
| C | 111 | 3 |
(左/右
熵
故
三、代码在做什么
demo.py 用堆实现 Huffman,打印码本、

四、小结
| 概念 | 一句话 |
|---|---|
| 前缀码 | 码字互不为前缀,可即时解 |
| 压不进熵以下(无失真) | |
| Huffman | 贪心合并最轻两棵树 |
| 下游 | 有噪改走 信道编码 |
下一章 信道编码。
📥 Code
| File | View | Download |
|---|---|---|
| demo.py | Open | Download |
| exercise.py | Open | Download |
参考
- Cover & Thomas, 第 5 章(Huffman)
- MacKay, ITILA