说到哈夫曼树大家应该都不陌生,它是一颗根据叶子节点权重进行构造的树,它能够使得树的带权路径长度最短。
而哈夫曼编码就是基于哈夫曼树,这是一个经典的压缩算法,可以根据权重给某个值分配一个01串,用这个较短的01串表达这个较长的值,权重越高的值的01串会越短,从而提高压缩率;
同时哈夫曼编码也是前缀不重复的,也就是不会有某个编码是另外一个编码的前缀,这样我们就能够把编码后的字符连续的存放,不需要其他额外的信息也能解码。
比如对于字符(a,b,c)对应的编码是:
| 字符 | 编码 |
|---|---|
| h | 110 |
| e | 111 |
| l | 10 |
| o | 0 |
可以看到上面的编码都不是其他编码的前缀,我们考虑对hello这个单词进行编码:11011110100,则解码过程就是从左读取,如果发现表里有对应的编码,则找到对应的字符,然后继续下一个字符解码:
| 当前编码值 | 字符 |
|---|---|
| 1 | |
| 11 | |
| 110 | h |
| 1 | |
| 11 | |
| 111 | e |
| 1 | |
| 10 | l |
| 1 | |
| 10 | l |
| 0 | o |
比如对于hello这个单词,我们可以知道每个字符出现的次数:
| 字符 | 出现次数 |
|---|---|
| h | 1 |
| e | 1 |
| l | 2 |
| o | 1 |
把这个出现次数作为每个字符的权重:

①选节点h和e(因为权重最小),生成新节点(绿色节点),新节点权重为h+e:

②选节点o和绿色节点(因为权重最小),生成新节点(蓝色节点),新节点权重为o+绿色节点:

③选节点l和蓝色节点(因为权重最小),生成新节点(红色节点),新节点权重为l+蓝色节点:

根据上面的树,按照往左走0,往右1,可以得到每个字符的编码:
| 字符 | 编码 |
|---|---|
| h | 110 |
| e | 111 |
| l | 0 |
| o | 10 |
根据上表则hello的编码为:1101110010,按照二进制为10位,也就是只需要两个字节就可以存储。比直接用hello的ASCII编码需要5个字节少3个字节。
了解HTTP2的同学肯定知道HTTP2是一个二进制协议,为了减小传输体积使用了头部压缩算法HPACK,算法有三个组成部分:静态表编码、动态表编码和哈夫曼编码。
为了使用哈夫曼编码,HPACK统计了大量HTTP头部,根据字符出现频率将ASCII编码为哈夫曼编码:
| 字符 | 编码 | 二进制长度 |
|---|---|---|
| '0' | 00000 | 5 |
| '1' | 00001 | 5 |
| '2' | 00010 | 5 |
| '3' | 011001 | 6 |
| 'A' | 100001 | 6 |
| 'B' | 1011101 | 7 |
| 'C' | 1011110 | 7 |
| 'D' | 1011111 | 7 |
通过减小出现频率高的字符的编码长度,从而减小整个HTTP头部的大小,提高传输效率,