哈夫曼编码,编码过程:

编码过程:哈夫曼编码是一种变长编码方法,用于数据压缩等场景,具体步骤如下:

首先,将字符出现的概率当作权值,构建哈夫曼树。这一步是基础,通过不断选取权值最小的两个节点合并,逐步生成树结构。
接着,按照 “左 0 右 1” 的规则给哈夫曼树的每条边标注。
然后,从根节点出发,到每个叶节点的 0 和 1 的组合,就成为该叶节点对应字符的编码。
最终,通过这样的方式得到各个字符的哈夫曼编码,能让出现概率高的字符获得较短编码,概率低的字符获得较长编码,从而实现数据压缩等目的。

题目一: 字母表 {a, b, c, d, e} 的频率分别为 10%,15%,30%,16%,29%。若使用哈夫曼编码方式对字母进行不定长的二进制编码,给出a、b、c、d、e分别对应的一组哈夫曼编码
题目二: 字符 {a, b, c, d, e, f} 的频率分别为 5%, 9%, 12%, 13%, 16%, 45%。请问 a、b、c、d、e、f 分别对应的一组哈夫曼编码

下面给出两道题的 完整哈夫曼编码过程、一步步合并(带图)以及最终编码和平均码长计算。注意:哈夫曼编码在合并权值相同时并非唯一——我给出的是一种常见且清晰的构造(把合并时的左子记为 0、右子记为 1),你也可以通过其他等价的 tie-breaking 得到不同但等价的编码。

题目一

字母表 {a,b,c,d,e} 的频率分别为 a:10%, b:15%, c:30%, d:16%, e:29%
目标:构造哈夫曼树并给出每个字母的二进制编码。

合并步骤(按权值从小到大合并两个最小)

初始节点(按频率从小到大列出):
a(10), b(15), d(16), e(29), c(30)

  1. 合并 a(10)b(15) → 新节点 ab(25)。(我们把 a 放左子记 0b 放右子记 1
  2. 此时节点:d(16), ab(25), e(29), c(30)。合并最小的 d(16)ab(25) → 新节点 d-ab(41)。(d0ab1
  3. 节点变为:e(29), c(30), d-ab(41)。合并 e(29)c(30) → 新节点 e-c(59)。(e0c1
  4. 最后合并 d-ab(41)e-c(59) → 根节点 100

对应的哈夫曼树(ASCII 示意)

              (100)
             /     \
         (41)       (59)
         /  \      /   \
      d(16) (25) e(29) c(30)
            / \
         a(10) b(15)

(每条左边分支记 0,右边分支记 1

从根到叶得到编码

  • d:根 → 左 (41) → 左 (d) ⇒ 00
  • a:根 → 左 (41) → 右 (25) → 左 (a) ⇒ 010
  • b:根 → 左 (41) → 右 (25) → 右 (b) ⇒ 011
  • e:根 → 右 (59) → 左 (e) ⇒ 10
  • c:根 → 右 (59) → 右 (c) ⇒ 11
字符 频率 编码
a 10% 010
b 15% 011
c 30% 11
d 16% 00
e 29% 10

平均码长计算(逐项算,确保精确)

平均码长 \(L=\sum p_i \times \ell_i\)

  • \(a\): \(0.10\times 3 = 0.30\)
  • \(b\): \(0.15\times 3 = 0.45\)
  • \(c\): \(0.30\times 2 = 0.60\)
  • \(d\): \(0.16\times 2 = 0.32\)
  • \(e\): \(0.29\times 2 = 0.58\)

合计 \(L = 0.30+0.45+0.60+0.32+0.58 = 2.25\)(比固定等长编码更短,说明压缩效果)


题目二

字符 {a,b,c,d,e,f} 的频率分别为 a:5%, b:9%, c:12%, d:13%, e:16%, f:45%
目标:给出一组哈夫曼编码并详细分析合并过程。

合并步骤

初始按频率从小到大: a(5), b(9), c(12), d(13), e(16), f(45)

  1. 合并 a(5)b(9)ab(14)。(a0b1
  2. 节点变为:ab(14), c(12), d(13), e(16), f(45)。合并 c(12)d(13)cd(25)。(c0d1
  3. 节点:ab(14), cd(25), e(16), f(45)。合并 ab(14)e(16)abe(30)。(ab0e1
  4. 节点:cd(25), abe(30), f(45)。合并 cd(25)abe(30)cd-abe(55)。(cd0abe1
  5. 最后合并 cd-abe(55)f(45) → 根 100

哈夫曼树(示意)

                 (100)
                /     \
           (55)         f(45)
           /  \
        (25)  (30)
        / \   /  \
     c(12)d(13) (14) e(16)
                / \
             a(5) b(9)

从根到叶得到编码

  • f:直接右子 ⇒ 1 (频率最大,码最短)

  • 在左子子树(以 0 开头):

    • c0 0 0000
    • d0 0 1001
    • e0 1 1011
    • a0 1 0 00100
    • b0 1 0 10101
字符 频率 编码
a 5% 0100
b 9% 0101
c 12% 000
d 13% 001
e 16% 011
f 45% 1

平均码长计算

逐项计算(以小数表示概率):

  • \(a\): \(0.05\times 4 = 0.20\)
  • \(b\): \(0.09\times 4 = 0.36\)
  • \(c\): \(0.12\times 3 = 0.36\)
  • \(d\): \(0.13\times 3 = 0.39\)
  • \(e\): \(0.16\times 3 = 0.48\)
  • \(f\): \(0.45\times 1 = 0.45\)

合计 \(L = 0.20+0.36+0.36+0.39+0.48+0.45 = 2.24\)(平均码长 2.24 bit)


额外说明(常见疑问)

  1. 唯一性:哈夫曼编码并不唯一。当多个节点频率相同或在排序时选择左右子顺序不同,会得到不同但等价的编码(平均码长相同)。上面两题给的是一种明确的 tie-breaking 规则(每次合并后把较小的放左或按我示例中的顺序),所以结果确定且便于说明。
  2. 前缀无冲突:哈夫曼编码是前缀码(prefix-free),即任一编码都不是另一个编码的前缀,便于无歧义地解码(树的叶子均为符号,非叶子无符号)。你可以从树结构直观验证:每个符号对应树的一个叶节点。
  3. 解码方法:读一串比特,从根出发按 0/1 走到叶子就得到了一个符号,然后回到根继续读后续比特。
  4. 最优性:哈夫曼算法在满足符号独立、按符号概率固定且按比特长度计成本时,能得到最小平均长度的前缀码(贪心最优)。

posted @ 2025-08-16 23:08  kkman2000  阅读(37)  评论(0)    收藏  举报