“长度选好后,规范Huffman码用符号顺序和码长表重建唯一的bit映射,并以整数空槽检查拒绝过订长度。这是码表表示与传输的接口,不重新证明或扩大本页的最优性范围。完整压缩流再规定EOF、位序…”
形式陈述
Huffman算法决定哪些符号获得哪些长度;规范化再决定同样长度下究竟使用哪些bit串。它的输入是有限符号表上的正整数码长
记
对每个长度
不能拿任意整数表直接移位建表。先验证符号不重复、长度属于
任何一步
直觉
想象按字典序摆放二叉树的叶。先分配较浅的叶,它的整棵后代就不能再用。进入下一层时,每个剩余空位分裂成两个位置,所以空位数先乘二,再扣掉本层叶数。上面的
首码递推也来自同一动作:长度
这一证明是Kraft可行性的具体构造。展开递推可得
例子与边界
给五字节 ABABA 加专用结束符EOF,EOF不是正文字符,它的编号为256。字节A、B分别编号65、66,顺序固定为
于是 A→0,B→10,EOF→11。发送 A B A B A EOF,有效位为 0|10|0|10|0|11 = 010010011。读者从根开始逐位走,分别在第1、3、4、6、7、9位输出A、B、A、B、A、EOF;末两位是结束符,不能当成正文。
收到长度 00,01,合法但不完整;输入以 1 开始会走进未用区域,应报告非法码流,不能补出一个默认符号。表里两条记录使用相同符号编号也必须拒绝,即使长度的Kraft和不大于一。
空文件仍要结束。本单元规定仅有EOF时给它长度1、码字 0,不采用零长度码。只有一个正文符号A的文件实际有A和EOF两个符号,所以码字为 0,1,可恢复重复次数。本教学文件的码长上限是15;普通Huffman建树若超过15,编码器明确拒绝,不能剪掉高位,也不能宣称自己实现了长度受限Huffman优化。
推论与应用
双方只交换“符号、长度”即可恢复码字,不需要交换每条根到叶路径。若符号表有
规范码经常用于真实压缩格式,但位序属于封装协议。RFC1951的DEFLATE把数据元素放到字节的低位起始位置,Huffman码字自身又按高位先出;本单元的教学文件统一按每字节高位先出,二者不能直接混读。完整表头、结束和填充规则见压缩流封装;检查器还用独立枚举空闲叶的方法检查340张小码长表。
需要保证最大码长时,可以先用package-merge得到保留符号身份的最优限长表,再应用本页同一首码递推。它补足的是选长度的优化步骤;这里已有的正码长、Kraft空槽、符号顺序和物理位序检查不变。既有HUF1编码器仍按其原规则在普通Huffman长度超过15时拒绝,并未隐式切换优化器。
参考资料
- L. Peter Deutsch,RFC1951,§3.1.1、§3.2.2:位打包与从长度恢复规范码;§3.2.7:动态码表的额外结构约束
- David A. Huffman,“A Method for the Construction of Minimum-Redundancy Codes”,1952:长度选择的原始最优性算法,见既有Huffman页的完整证明