CSP初赛-哈夫曼树
题目一:
字母表 {a, b, c, d, e} 的频率分别为 10%,15%,30%,16%,29%。若使用哈夫曼编码方式对字母进行不定长的二进制编码,字母 d 的编码长度( )位。
选项:
A. 1
B. 2
C. 2 或 3
D. 3
题目二:
字符 {a, b, c, d, e, f} 的频率分别为 5%, 9%, 12%, 13%, 16%, 45%。请问以下哪个选项是字符 a、b、c、d、e、f 分别对应的一组哈夫曼编码?
选项:
A. 1111, 1110, 101, 100, 110, 0
B. 1010, 1001, 1000, 011, 010, 00
C. 000, 001, 010, 011, 10, 11
D. 1010, 1011, 110, 111, 00, 01
这里的“前缀无冲突”,就是在说前缀码(prefix-free code):
对任意两个不同的码字 \(x\neq y\),都不允许 \(x\) 是 \(y\) 的前缀。这样解码时,从左到右读比特,一旦读到某个码字,就能立刻确定对应字符并输出(不用再看后面的比特)——这叫即时可译(instantaneous decoding)。
为什么要“前缀无冲突”?
- 即时解码:读到叶子(完整码字)就停,输出一个字符,继续从根读下一段,比特流可在线逐个符号解出。
- 避免歧义:如果存在前缀关系,解码器在读到短码字时就会犹豫:这是一个完整符号,还是更长码字的开头?这会导致需要回看/前瞻,甚至可能造成不唯一解码。
用你题里的选项 A 来看
选项 A(按 a,b,c,d,e,f 顺序):
1111, 1110, 101, 100, 110, 0
它的长度分别是:a=4, b=4, c=3, d=3, e=3, f=1。检查“前缀无冲突”只需看有没有码字是另一码字的前缀:
0的后面有没有以0开头的更长码字?没有(其它都以1开头或先导为1)。- 以
1开头的三位码:100,101,110之间互不为彼此前缀;四位码1110,1111也互不为前缀;三位码也不是四位码的前缀(后三位不同)。
因此它是前缀码,解码时一旦读到0就立刻输出f;读到1110就立刻输出b,等等,毫不含糊。
(顺便一提,哈夫曼算法总是产出前缀码;哈夫曼树里,只有叶子结点才对应码字,内部结点不会对应码字,这正是“前缀无冲突”的结构性保证。)
形象理解(用二叉树/字典树)
把每个码字当作从根出发:读 0 走左,读 1 走右。
“前缀无冲突” ⇔ 所有码字都在叶子上,且没有一个码字停在别的码字之上(即没有码字对应内部结点)。
一旦走到叶子就输出字符并回到根,继续读后面的比特。
一个“有冲突”的反例
假设有码集合 {0, 01, 111}:
- 这里
0是01的前缀。 - 当比特流是
01...时,读到第一个0,你不敢立刻输出,因为它也可能是更长的01的开头;这就不是即时的。更糟的是,在某些集合里还会引起不唯一解码(存在多种切分方式得到不同字符串)。
快速检查方法
-
排序/逐对检查:看是否存在“短码字 = 长码字的前缀”。
-
Trie(字典树)法:把码字插入一棵二叉 Trie,插入过程中若:
- 走到一个已经是“叶(已作为码字终止)”的结点还想继续往下走,或
- 刚把当前结点标为“叶”,却发现它已有子结点,
就说明存在前缀冲突。
额外小知识:Kraft 等式
对二进制前缀码,长度集合 \(\{l_i\}\) 必满足 Kraft 不等式
\(\sum 2^{-l_i} \le 1\)。
选项 A 的长度是 $ {4,4,3,3,3,1}\(,计算
\)\tfrac{1}{16}+\tfrac{1}{16}+\tfrac{1}{8}+\tfrac{1}{8}+\tfrac{1}{8}+\tfrac{1}{2} = 1$,
等号成立,说明这是一棵“满”的前缀码树,也从侧面验证了“前缀无冲突”。
第一题:字母d的哈夫曼编码长度
要确定字母d的编码长度,需遵循哈夫曼编码的核心步骤(合并最小频率节点),具体过程如下:
步骤1:整理频率(按从小到大排序)
- a: 10%,b: 15%,d: 16%,e: 29%,c: 30%
步骤2:逐步合并最小频率节点
- 第一次合并:最小的两个频率(a:10% + b:15%)= 25%,新节点为25%。
剩余节点:d:16%,25%(a+b),e:29%,c:30%。 - 第二次合并:最小的两个频率(d:16% + 25%)= 41%,新节点为41%。
剩余节点:e:29%,c:30%,41%(d+a+b)。 - 第三次合并:最小的两个频率(e:29% + c:30%)= 59%,新节点为59%。
剩余节点:41%(d+a+b),59%(e+c)。 - 第四次合并:41% + 59% = 100%,完成树的构建。
步骤3:确定d的编码长度
在哈夫曼树中,每个叶子节点的编码长度等于其到根节点的路径长度(左支为0、右支为1,或反之,不影响长度)。d在第二次合并中作为叶子节点,路径需经过2个分支,因此编码长度为2位。
答案:B
第二题:字符abcdef的哈夫曼编码验证
关键前提
- 哈夫曼编码是前缀编码(任一编码不是其他编码的前缀);
- 频率最高的字符编码最短,频率最低的编码最长(频率:f:45% > e:16% > d:13% > c:12% > b:9% > a:5%,对应编码长度应递减)。
选项逐一排除
-
选项A:编码为1111(a)、1110(b)、101(c)、100(d)、110(e)、0(f)
验证:①前缀性:无编码是其他编码的前缀;②长度匹配:f(1位,最高频) > e(3位)、d(3位)、c(3位) > b(4位)、a(4位,最低频),符合频率-长度递减关系。暂符合。 -
选项B:编码为1010(a)、1001(b)、1000(c)、011(d)、010(e)、00(f)
验证:频率最高的f编码为2位,但e(16%)编码也为2位(与f相同),且d(13%)、c(12%)编码也为3位(与b、a的4位差距不匹配频率递减),不符合“最高频编码最短”原则。排除。 -
选项C:编码为000(a)、001(b)、010(c)、011(d)、10(e)、11(f)
验证:频率最高的f编码为2位,但e(16%)编码也为2位(与f相同),且最低频的a、b编码为3位(应最长),但d(13%)、c(12%)编码也为3位(与a、b相同),不符合频率-长度对应关系。排除。 -
选项D:编码为1010(a)、1011(b)、110(c)、111(d)、00(e)、01(f)
验证:频率最高的f编码为2位,但e(16%)编码也为2位(与f相同),且d(13%)、c(12%)编码为3位(应短于a、b的4位,符合),但“最高频f未获得最短编码(1位)”,不符合哈夫曼编码逻辑。排除。
答案:A
答案:
1)关于 {a,b,c,d,e} 频率 10%、15%、30%、16%、29%,字母 d 的哈夫曼码长度:
合并过程:10+15→25;再 16+25→41;再 29+30→59;最后 41+59→100。
得到叶深度:a=3,b=3,c=2,d=2,e=2。
⇒ 选 B. 2
2){a,b,c,d,e,f} 频率 5%、9%、12%、13%、16%、45% 的一组哈夫曼编码:
合并:5+9=14;12+13=25;14+16=30;25+30=55;45+55=100。
叶深度可为:a=4,b=4,c=3,d=3,e=3,f=1。
在选项中,只有 A(a,b,c,d,e,f 对应 1111,1110,101,100,110,0)满足该长度分配且前缀无冲突。
⇒ 选 A

浙公网安备 33010602011771号