学习首页/贪心与回溯/哈夫曼编码交互演示 · JavaScript

代码与动画 HUFFMAN CODING

哈夫曼编码.

反复合并频次最小的两棵树,沿树的左右分支生成前缀编码。

排序选最小:O(n² log n)空间 O(n)可变长前缀编码

原理与执行逻辑

以字符频次为叶权重,每次合并最小的两棵候选树。由根到叶读取左右分支的 0、1 标签,生成总加权编码长度最小的前缀编码。

执行步骤

  1. 为每个字符建立一棵只有叶节点的树。
  2. 将候选按权重排序,取出最小的两棵。
  3. 创建权重等于两者之和的父节点,将合并树放回候选集。
  4. 剩一棵树后遍历,左分支追加 0、右分支追加 1,输出每个字符编码。

关键理解

字符都在叶节点,因此一个字符编码不会成为另一个的前缀。每次合并会令子树全部叶子的码长增加 1,成本恰好是两棵子树权重之和。

简短示例

A:2、B:3、C:7 先合并 A 与 B 为 5,再与 C 合并。可得到 A=00、B=01、C=1,总加权位数为 2×2 + 3×2 + 7×1 = 17。

代码与执行动画

STEP 0 / 14
哈夫曼编码
function huffman(entries) {  let serial = 0;  const queue = entries.map(([symbol, weight]) => ({symbol, weight, order: serial++}));  while (queue.length > 1) {    queue.sort((a, b) => a.weight - b.weight || a.order - b.order);    const left = queue.shift(), right = queue.shift();    queue.push({weight: left.weight + right.weight, left, right, order: serial++});  }  const codes = {};  function visit(node, prefix) {    if (node.symbol !== undefined) { codes[node.symbol] = prefix || '0'; return; }    visit(node.left, prefix + '0'); visit(node.right, prefix + '1');  }  visit(queue[0], '');  return codes;}
16 行 · 0 个片段标记
候选树 5
5A9B12C13D16E
当前数据正在操作已访问 / 命中标记 / 指针
0

初始化字符树

每个字符独立成树,节点值是出现频次。

配置演示数据

应用后重新生成执行过程,可单步观察结果。

实现说明

哈夫曼编码的操作规则

本演示每轮对候选树排序,左边标 0,右边标 1。相同频次按创建顺序选择;单字符编码约定为 0。输出编码与总加权位数。

对应题目与扩展练习

观察执行过程后,按题目约束调整输入、返回值与实现。链接打开官方题目页面。