形式陈述
输入是带固定身份的整数 个符号、正整数权重 和整数最大码长 。输出保留符号身份的整数长度 ,满足
并在全部二元前缀码理路前缀码Prefix-free code码字互不为前缀并保留单射源标签的编码;正码长时可即时译码。中最小化 。权重不必归一化成概率。若 ,报告不可行;反之全取长度 就满足Kraft条件,因而可行。若 ,按本格式的正码长约定输出1,不采用空码字。零权重在本接口中拒绝:不能悄悄删掉仍须编码的符号。下面讨论 。
package-merge 把符号 在每层 复制为一个物品 ,宽度 ,代价 。要求选出总宽度恰为 的最小代价物品集,称为nodeset。每个物品仍有自己唯一的“符号、层”身份。
实现先按权重及符号序排好一份表,初始化最深层 。只对当前深度 执行下面步骤1、2;进入层1后直接执行步骤3、4,不再配对:
- 把当前层已排序物品从最轻开始两两配成包;包宽度加倍、代价相加,并保存两个孩子。若数量为奇数,丢掉最重的剩余项
- 把这些包与下一浅层的 个原始物品线性归并,保持代价顺序
- 到层1时,每项宽度均为 ,取最轻的 项;若数量不足则不可行
- 沿所选包的树回溯到原始物品。符号 被选的物品数就是
同权重使用确定的规则:先按 分配秩 ;原始项的比较键为 ,包逐分量相加,再以唯一创建序号打破完全相同的键。它等价于微扰权重 ,其中 。所有候选集的秩和不超过 ,所以这种比较先优化原整数成本,再确定平局;实现不使用浮点微小数。
直觉
普通Huffman算法理路Huffman 编码Huffman coding反复合并最低概率符号构造期望码长最小前缀码的算法。可以不断把最轻项推向更深层;但存在最大深度后,最深层的位置变成有限资源。package-merge在每个允许深度上放置一份“再增加一层码长的费用”。是否给某符号增加一层,不能独立决定:物品宽度必须合成同一个总数。
从配对包回溯到合法长度 配对归并为什么优化硬币问题
更一般地,设物品宽度均为2的整数次幂,目标宽度为 ,最小现有宽度为 。所有更大宽度都是 的倍数。如果 为奇数,合法选择必须含奇数个宽度 的项,至少一个;交换同宽物品可让某个最优解包含其中最轻项,先取它并将目标减 。如果目标为 的倍数,则必须选偶数个最细项。
固定要选的数目 后,同宽交换使所选项可取为最轻的前 个,即从最轻开始的 对。于是相邻两项可以绑定成“同进同出”的包,在下一宽度层继续优化;最重的奇数余项不可能进入这种最轻偶数前缀。包的权重保持排序,因为相邻对的两项都不重于下一对的对应项。归纳到更大宽度,配对和归并都不改变最优值,最后回溯展开包即可。
本问题 是整数。宽度小于 时, 总是该宽度的偶数倍,所以各层只需配对;到 时选择恰好 项即可。不必运行穷举或动态规划来替代配对算法。
为什么所选物品真的给出合法码树
第一步是从树到物品。正权重最优前缀树不含单孩子内部节点,否则收缩该边会减少成本且不会破坏上限。因此可以选满二叉树,Kraft和等于1。若叶 深度为 ,选它的 ,则
因此硬币最优值不大于最优树成本。但这还没有证明反向转换,需要排除一个符号“选了深层却漏了浅层”的非法集合。
二进制余量引理。 若一组二进制宽度物品的总宽为 , 为非负整数,,则有子集宽度恰为 。按物品数归纳:最小宽度 必小于 ,否则总宽没有这个余量; 也是 的整数倍,故 。若 取此项;否则删掉此项,对余量 应用归纳,再把它放回。
现在若最小代价nodeset 包含 、,却不含 ,将前者换成后者得到 ,成本不变,宽度从整数 增为 。对基准宽度 应用余量引理,能从 删掉总宽恰为 的非空子集,重新得到宽 ,而正权重保证成本严格降低,矛盾。故每个符号的所选层连续地从1开始。
令 为所选层数,包括可能的0。于是同一几何级数公式给出 。若有 ,它本身贡献1,其余 个有限长度各贡献正数,与等式矛盾。因此全部 。由Kraft充分性理路Kraft–McMillan 不等式Kraft–McMillan inequality刻画给定码长集合存在前缀码或唯一可译码的必要充分不等式。存在相同长度的前缀树;其成本等于硬币最优值,所以也等于限长树的最优值。该证明甚至不需所有原权重互异;微扰只是确定一个可复现的最优答案。最后用规范码长表理路规范Huffman码与码长表Canonical Huffman code · 规范赫夫曼码从带符号的码长表唯一重建码字,以整数空槽检查拒绝过订长度,并逐位解出含EOF的短流。恢复具体码字,不重新优化长度。
例子与边界
权重按符号A至F为 ,令 。只列主权重,实际仍保留符号和层身份:
- 层3原始表:
1,1,2,3,5,8;配成 2,5,13
- 层2将这些包与六个原始项归并:
1,1,2,2,3,5,5,8,13;再配成 2,4,8,13,剩余13丢弃
- 层1归并:
1,1,2,2,3,4,5,8,8,13;恰取全部10项,总宽 ,代价47
回溯选中层1、2的全部六个符号,以及层3的A、B、C、D。所以长度是 ,成本
Kraft和 。规范化得到 A=100,B=101,C=110,D=111,E=00,F=01。每个符号出现 次的20符号消息正文恰47bit;传表和终止仍须另计。
普通Huffman的一组最优长度是 ,成本45,却超过限制。把过长项直接截成3得到 ,Kraft和 ,连可译长度都不是。优化不是逐项裁剪。
独立穷举每个 并检查整数Kraft条件,共有22个可行长度向量;47的最优向量唯一。这是核对实现的独立oracle,不是正文算法,也不是最优性的普遍证明。两个等权符号交换码字仍可产生不同树,“长度向量唯一”不表示所有标边方式唯一。
时六符号不可能; 时本确定规则输出 ,成本46,共有3个最优长度向量; 恢复成本45。增加上限只扩大可行集,所以最优值不增,不能声称每次一定严格降低。等权 、 有三种最优长度向量,本实现确定输出 ,成本5。
推论与应用
复杂度应包含排序、包树和输出
初始排序 ,每层原始项是同一排序的复制。列表长度递推 ,所以每层配对及双指针归并 ,共 。所存原始项和包节点为 ;回溯只访问所选包树,每个原始物品唯一、每个节点至多一个父包,总访问 。故本版本时间 、空间 ,不把论文另外的线性空间重算技术算作已经实现。
重建长度数组另需 ;规范码的整数表在符号顺序已知时用稳定码长桶构造,需 ,检查器也采用此方法,若写出每条完整bit串还要 ,最坏 。若权重是大整数,比较与加法还须计位复杂度。检查器限制 ,任一包的主成本小于 ,秩和至多 ,64位无符号整数足够存这些量;所有宽度以整数 比较,需可容纳 ,不能只用32位值。
长度上限约束的是最深叶及相应译码路径;它不直接最小化建表内存、整份文件大小或缓存延迟。若频数由当前文件得到,码长表仍应传给接收者。原有HUF1编码器超过15仍明确拒绝;只有显式把其“选长度”步骤换成这里的优化器并保留EOF、符号身份及整个格式检查,才算完成限长编码扩展。本单元不暗改已有HUF1文件或默认实现。
终点实验把限制从3改成2、4、5,回溯全部符号,再核对规范码。检查器对486个小权重实例比较真实package-merge与独立Kraft穷举,并保留所选nodeset;有限测试不是对任意输入的证明。
参考资料