首页/数据结构/04-tree/哈夫曼树和哈夫曼编码 🔗 在 Obsidian 中打开
数据结构 · 04-tree

哈夫曼树和哈夫曼编码

重要度 ⭐⭐⭐⭐⭐ 哈夫曼树哈夫曼编码最优二叉树前缀编码带权路径长度贪心
速查
$WPL = \sum_{i=1}^{n} w_i l_i$;每次选权值最小两个合并。n 个叶子的哈夫曼树有 2n−1 个结点、无度 1 结点;WPL = 所有非叶子权值之和。编码是前缀编码

核心概念

结点的权:赋予结点的有意义的数值。带权路径长度(WPL):从根到该结点的路径长度 $\times$ 结点权值。树的 WPL = 所有叶子带权路径之和:

$$WPL = \sum_{i=1}^{n} w_i l_i$$

哈夫曼树(最优二叉树):在含 n 个带权叶子的二叉树中 WPL 最小者。特点:

  • 没有度为 1 的结点($n_1 = 0$);
  • n 个叶子 → 共 2n−1 个结点($n_0=n$,$n_2=n-1$);
  • 哈夫曼树不唯一,但 WPL 唯一。

构造与编码

哈夫曼算法(贪心)

  1. n 个结点作 n 棵只含根结点的树,构成森林 F;
  2. 在 F 中选两棵权值最小的树,作为新结点的左右子树,新结点权值 = 二者之和;
  3. 从 F 中删除这两棵树,把新树加入 F;
  4. 重复 2、3 直到只剩一棵树。
编码规则从根到子树分支标 0、右子树标 1;每个字符的编码 = 根到该字符叶子的 0/1 序列。前缀编码:没有任一编码是另一编码的前缀,WPL 最小即编码总长最短。

编解码

编码:字符 → 对应哈夫曼编码(如 "FACE" → "11 1000 101 01")。解码:从根开始读 0 走左、读 1 走右,到叶子输出字符(如 "11100010101" → F A C E)。

手算示例

例 1 · 编码({2,3,5,7,8,11})

字符权值编码(约定左 0 右 1)
A21000
B31001
C5101
D700
E801
F1111

例 2 · WPL({3,5,7,8,11,14})

合并:3+5=8,7+8=15,8+11=19,14+15=29,19+29=48。简化计算:$WPL =$ 所有非叶子结点权值之和 $=8+15+19+29+48=119$(每次合并两权值各计一次路径)。

易错点

易错清单
  1. n 个叶子有 2n−1 个结点,不是 2n。
  2. 哈夫曼树没有度为 1 的结点:$n_1 = 0$。
  3. WPL = 所有非叶子结点权值之和(简化计算)。
  4. 哈夫曼编码是前缀编码,不会产生歧义。
  5. 构造时选最小两个;权值相同任选。

核心结论

属性
叶子数n
总结点数2n−1
度为 1 的结点0
WPL$\sum w_i l_i$(= 非叶子权值之和)
编码性质前缀编码

记忆卡片

n 个叶子的哈夫曼树有多少结点?
2n−1。
哈夫曼树有度为 1 的结点吗?
没有,$n_1=0$。
WPL 的简化计算方法?
所有非叶子结点权值之和。
构造时每次选几个结点合并?
选权值最小的两个。

交互动画 · 构造 + 读码

权值 {3,5,7,8,11,14}:灰=叶子,绿=内部结点;橙虚线=本次合并 01 01 01 01 01 48 19 29 8 11 14 15 3 5 7 8
森林:{3,5,7,8,11,14} —— 每次选两棵权值最小的合并
点「合并 · 下一步」逐步建树;WPL = 所有内部结点之和 = 119
读码即从根出发,沿 0 左 / 1 右到叶子;各编码长度 = 叶子深度,编码总长即 WPL。

相关知识点

binary-tree-traversal binary-search-tree avl-tree internal-sorting-comparison binary-tree-properties

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。