首页 › programming › 哈夫曼神课:最优从何而来

哈夫曼神课:最优从何而来——Reducible《How Huffman Coding Works》深度解读

概述

压缩是计算机科学里少有的“每天摸得到”的理论:你解压一个 zip、打开一张 JPEG、听一首 MP3,背后都站着同一个名字——哈夫曼编码。而把它讲得最透的,是 YouTube 知识频道 Reducible 的《How Huffman Coding Works》。这条视频从摩尔斯电码讲起,一步步推到前缀码、贪心构造与最优性证明,最后诚实交代了它够不着香农熵的那一截。本文按视频叙事顺序逐层拆解,补上视频里一笔带过的数学细节(Kraft 不等式、交换论证、规范哈夫曼、ANS),并给出批判性审查与可操作的建议——看过视频的人能补全证明思路,没看过的人能直接吸收全部精华。

视频基本信息

项目 信息
视频标题 How Huffman Coding Works(哈夫曼编码是如何工作的)
频道 Reducible
发布时间 2021年(据频道页面,本文未能实时核验具体日期)
热度 数百万量级播放,为该频道代表性爆款之一(据频道页面)
类型 算法可视化讲解 / 动画科普

需要说明的是:本文写作时未能实时抓取视频页面,以上数据按频道页面信息整理,播放量与发布日期的具体数字以频道当前显示为准。这不影响内容解读——这条视频自发布以来长期被算法反复推荐,属于典型的“常青神课”,至今仍是哈夫曼主题下引用最多的可视化讲解。


一、从摩尔斯电码说起:频率就是钱

视频的开场没有直接抛公式,而是回到 1830 年代的电报时代。摩尔斯电码里最著名的细节是:字母 E 只用一个点(·)表示,T 只用一横(—)表示——因为它们是英文里出现频率最高的字母;而罕见如 Q、Z 则要敲上四下。这个设计在今天看来就是一次朴素的“压缩”:给高频符号发短码,给低频符号发长码,整体传输成本就下来了。

视频随后把这套直觉形式化。假设有一段文本,用等长编码给每个字符分配相同位数的二进制码,那么总比特数 = 字符数 × 每字符位数。但真实文本的字符频率极不均匀:英文中 E、T、A、O 加起来占了近三成,而 J、Q、X、Z 合计不到 0.5%。等长编码等于强迫低频字符“陪跑”了大量的比特预算。

这里值得补一层视频没有展开的量化背景:Claude Shannon 在 1948 年那篇《A Mathematical Theory of Communication》里给出了信息熵的定义——H = −Σ pᵢ log₂ pᵢ,单位比特/符号。它划定了压缩的理论下界:任何无损编码,平均每符号码长不可能低于信源的熵。摩尔斯电码的发明者在没有这个理论的一百年前,靠直觉摸到了它的边缘。哈夫曼编码的全部故事,就是“如何在离散、逐符号的约束下,尽量贴近这条下界”的故事。

二、变长编码的第一坑:歧义

既然高频给短码能省钱,最直接的做法就是按频率排个序,从短到长分配 0、1、10、11、100……视频在这里放了第一个转折:这样做的结果是解码歧义。

举例说明:假设 a = 0,b = 1,c = 10。收到串 10,你无法判断它是“c”,还是“b、a”。变长编码一旦失去边界标记,一段合法的比特流可能对应多种原文,压缩就失去了意义。工程上管这个性质叫唯一可解码性(uniquely decodable),更进一步还有即时解码(instantaneously decodable)——读到哪、解到哪,不用回头看,也不用向前猜。

这个小节是整条视频的第一块认知地基:压缩的本质不是“把码变短”,而是在保证无歧义的前提下把码变短。约束变了,问题就从“拍脑袋分配”变成了一个结构问题。

三、前缀码:把句子种成一棵树

解决歧义的钥匙是前缀码(prefix code):任何一个码字都不能是另一个码字的前缀。上面反例里 c=10 之所以出事,是因为它是前缀组合的牺牲品——10 恰好可以被 b=1 与 a=0 拼出来。前缀性质封死这类组合。

视频用二叉树把前缀码画活了:所有码字放在树的叶子上,往左走是 0,往右走是 1。因为码字只在叶子上,从根到任何一个叶子的路径都不可能是到另一个叶子的路径的前缀(你走到叶子就停了,不可能“路过”一个叶子还在往下走)。解码就是从根出发按比特走路,走到叶子输出一个字符,回到根继续。

这里补一个视频里没有点名的数学事实——Kraft–McMillan 不等式:一组码长为 l₁, l₂, …, lₙ 的前缀码存在,当且仅当 Σ 2^(−lᵢ) ≤ 1。它解释了两件深层的事:

  1. 为什么前缀码必然对应一棵二叉树:每个码长为 l 的码字“占用”了满二叉树里 2^(−l) 的长度预算,所有码字加起来不得超过整棵树的预算 1。
  2. 为什么研究前缀码就够了:Kraft–McMillan 定理同时证明了,任何唯一可解码码(哪怕它解码要延迟)都能被一个同码长的前缀码替代。也就是说,前缀码在码长分布上不输给任何编码方案——把搜索空间缩小到二叉树,不会漏掉更优的解。

这两点合起来,把“如何设计最优压缩码”干净地转化成了“如何造一棵总加权路径长度最小的二叉树”。这个转化是哈夫曼算法登场前最关键的一步棋。

四、香农-范诺:自上而下的差一步

视频接下来讲了历史上第一个系统性方案:香农-范诺编码(Shannon–Fano coding)。思路是“自上而下”:把所有符号按频率排序,从中间切一刀,让上下两半的频率和尽量相等;上半边分配前缀 0,下半边分配 1;然后对两半递归。直觉很漂亮——每次都把概率质量对半分,理论上每深入一层,就该消耗掉约一比特的信息。

它确实有效,而且能达到不错的效果。但视频用了一个具体例子展示它的软肋:对半分的切法不一定切在最优的位置上。某些频率分布下,一刀切的递归会把本该配成短码的符号拆散,得到比理论最优更长的平均码长。问题出在方法论上:它是一个“看起来合理”的启发式,而不是一个被证明最优的算法。差的那一步,一等就是几年,等一个 MIT 的研究生在期末周交出的作业。

五、1952年那门课:哈夫曼的逆操作

这是全视频最有戏剧性的一段,也是真实的历史:1952 年,MIT 的 David Huffman 修读 Robert Fano 的课程。Fano 本人与 Shannon 已经在这个问题上摸了很久——前面那套“自上而下对半分”正是 Shannon 与 Fano 各自独立提出的方法,而 Fano 清楚它没被证明最优。据课程作业的流传记载(这一典故被 Huffman 本人在多次访谈中确认,也收录于 Wikipedia 的 Huffman coding 词条),Fano 给全班一道选择题:要么参加期末考试,要么完成一个问题集。Huffman 选择了后者,其中就有“找出最优二进制码”这题。他折腾了几个月毫无头绪,几乎要放弃去修学分,然后在某个瞬间想到了那个逆操作:

别从上往下分,从下往上合。

哈夫曼算法由此诞生,步骤极简:

  1. 把每个符号看作一棵单节点树,权重为它的频率,全部放进优先队列(最小堆);
  2. 取出权重最小的两棵树,合并成一棵新树,新根的权重为两者之和,原来的两棵分别是左右子树;
  3. 把新树放回队列;
  4. 重复步骤 2–3,直到队列里只剩一棵树——它就是哈夫曼树;
  5. 从根到每个叶子走一遍,左 0 右 1,读出每个符号的码字。

视频的动画在这一段做得最直观:小频率的符号先被“吞掉”,一层层往上合并,最后频率最高的字符待在树的最浅层、拿到最短的码。整个算法用最小堆实现,n 个符号只需 O(n log n)。

补一层背景:Huffman 后来把成果写成论文《A Method for the Construction of Minimum-Redundancy Codes》,发表于 1952 年的 Proceedings of the IRE。这篇诞生于课程作业的论文,成了数据压缩领域被引用最多的文献之一。而 Fano 的反应后来也被反复引用——他承认自己的方法被学生超越了,并把这个问题从课堂练习中撤了下来。

六、为什么它是最优的:交换论证

视频明确说了一句“哈夫曼编码是最优的”,但没有展开证明。这是本文要替你补上的“多懂一层”:这个最优性不是靠跑分跑出来的,而是有一个教科书级的交换论证(exchange argument),思路如下:

这套“交换论证”是算法课里证明贪心正确的标准武器(贪心区间调度、Kruskal 最小生成树用的都是同一思路)。哈夫曼算法与贪心理论的这层关系,视频只擦了个边:它是最小生成树之外,贪心算法最漂亮的应用之一。顺带一提,“合并果子”“文件合并最小成本”这类经典算法题,本质全是哈夫曼。

七、够不着的熵:整比特的宿命

视频最诚实的地方在结尾:它没有把哈夫曼封神,而是点出了它的天花板。假设一个信源只有两个符号,其中 P(A) = 0.9、P(B) = 0.1。它的熵是:

H = −0.9·log₂0.9 − 0.1·log₂0.1 ≈ 0.469 比特/符号

但哈夫曼树在这个场景下只有一个形状:两个叶子,各分得 1 比特。平均码长 1 比特,比理论下界 0.469 高出一倍多,压缩效率只有约 47%。病根在于逐符号编码必须分配整数比特——你不能给一个字符发“0.469 个比特”。

出路视频也指了方向:把多个符号捆在一起编码。按 Shannon 的信源编码定理,将 n 个符号作为一组联合编码,平均每符号码长可以任意逼近熵。这一思想的两个工程后代:

哈夫曼没有因此退场,而是退到了“性价比之王”的位置:实现极简、解码极快、无专利包袱,在速度敏感的场景里至今仍是默认选项。

八、它在哪:DEFLATE、JPEG、MP3 与规范哈夫曼

视频最后把镜头拉回现实,值得逐个展开——这也是“看过视频还能多懂一层”最厚实的一节:

这里藏着一个精妙的工程细节,视频没有展开,但它最能体现“哈夫曼思想的工业化变形”——规范哈夫曼码(canonical Huffman code)。DEFLATE 并不在文件里存整棵树,而只存“每个码长的符号有多少个”这样一张极小的表,双方按同一套确定规则(同长度内按符号字典序编号)各自重建码表。这样做有两个好处:码表体积骤减;码字本身有了字典序,可以用简单整数比较完成某些查找。你在解压任何一个 zip 时跑的,都是这套七十年前课程作业的后代。

再往后的 zstd、brotli 则展示了现代哲学:LZ 匹配 + 熵编码(FSE/ANS 或哈夫曼)+ 上下文建模,多级流水线协作,在压缩率与解压速度之间重新谈判。哈夫曼在这条流水线里常常还在,只是不再独挑大梁。

九、批判性审查:三个成立前提

视频作为教学作品质量极高,但“最优”一词需要读者自带脚注。哈夫曼的最优性严格成立于三个前提之下,打破任何一条它就不再是最优:

前提一:逐符号、整比特编码。 上面 0.9/0.1 的例子已经说明——这是它够不着熵的根源。算术编码与 ANS 正是从这里突破的。

前提二:符号频率已知且相互独立。 哈夫曼树是为特定频率分布定制的。实际文本中符号之间高度相关(q 后面几乎必然跟 u),逐符号模型看不见这种相关性,LZ 系列的字典方法因此效率更高。工程上还需两遍扫描(先统计再编码)或自适应哈夫曼(Vitter 1987 年提出的算法可一边读一边动态更新码树,代价是复杂度上升)。

前提三:“最优”的参照系是全体前缀码。 视频叙事里哈夫曼“打败”香农-范诺,严格说香农-范诺在部分频率分布下也能碰巧达到最优;准确表述是:哈夫曼在所有前缀码中保证平均码长最小,而香农-范诺不保证。这是叙事效率与数学严谨之间的常见取舍,视频中大部分结论均站得住,唯独“最优”二字需要上述限定。

另有一处值得较真:视频把历史讲成“Huffman 击败了老师 Fano”,大方向属实,但 Shannon 与 Fano 的工作为前缀码、熵与码长界定了问题空间——没有这些地基,那个“逆操作”没有意义。科学的常态不是天才单杀,而是接力。

十、认知提升与实用启示

启示一:用“交换论证”审查你的一切贪心决策。 无论是算法题里的贪心策略,还是产品里的“先做最痛的点”,贪心直觉都可能是错的。哈夫曼给出的范式是:先证明“最优解里最贵的部分恰好是贪心要处理的部分”(最深的叶子恰好是最小频率的兄弟),再证明“处理完可归约为同构子问题”。两步走完,贪心才从“看起来对”升级为“一定对”。下次你写任务调度、合并文件、区间排程时,值得照此模板推一遍。

启示二:拆任何文件格式,先找熵编码层。 想手撕 JPEG 或取证一个 zip?入口就是码表:JPEG 的 DHT 段、DEFLATE 头里的 HLIT/HDIST 码长分布。理解了规范哈夫曼“只存码长、双方重建”的约定,你甚至可以不依赖任何库,手写一个 gzip 解码器——这是理解“格式即协议”的最佳练手项目。

启示三:工程选型学 zstd 的中间道路。 极限压缩比(算术编码/上下文建模)与极简速度(哈夫曼)之间存在一条被现代工业反复验证的中间道路:用足够好的算法 + 极致的实现速度取胜。选型时的正确问法不是“哪个理论最优”,而是“在我的流量、CPU 预算、解压端约束下,哪个的端到端性价比最高”。

视频论证结构图

flowchart TD
    A[摩尔斯电码的启示<br/>高频符号配短码] --> B[香农熵<br/>压缩的理论下界]
    B --> C[变长编码的第一坑<br/>解码歧义]
    C --> D[前缀码与二叉树<br/>码字只放叶子上]
    D --> E[香农-范诺编码<br/>自上而下对半分]
    E --> F{被证明最优了吗?}
    F -->|没有| G[哈夫曼的逆操作<br/>自下而上两两合并]
    G --> H[交换论证<br/>最优性的完整证明]
    H --> I[整比特的宿命<br/>够不着的熵下界]
    I --> J[算术编码与ANS<br/>逼近理论极限]
    G --> K[现实落点<br/>ZIP/JPEG/MP3码表]

延伸阅读

  1. Computerphile《Entropy in Compression》 — Dr. Mike Pound 用实例讲香农熵如何给压缩划定极限,与本条视频构成“理论+算法”的完整闭环,可在 YouTube 搜索标题直达。
  2. David A. Huffman, "A Method for the Construction of Minimum-Redundancy Codes", Proceedings of the IRE, 1952 — 那份课程作业的原始论文,正文仅数页,读完你会发现视频里的每一步动画都严格对应论文的一个小节。

参考来源

  1. Reducible 频道页 — 《How Huffman Coding Works》发布频道;本文未能实时抓取视频页,标题、时间与热度据频道页面整理
  2. Huffman coding - Wikipedia — 哈夫曼算法、1952年课程作业典故与 Kraft 不等式
  3. Shannon's source coding theorem - Wikipedia — 熵下界与信源编码定理
  4. Asymmetric numeral systems - Wikipedia — ANS 在 zstd/AV1/JPEG XL 中的应用

本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入