3.Huffman编码
Huffman编码的思路也非常容易理解,就是采用变长编码,减少高频字符的码长,增加低频字符的码长。
Huffman编码是一种前缀码(即没有任何码字是其他码字的前缀)。与任何字符编码相比,前缀码可以保证达到最优数据压缩率,并简化解码过程。
我们这样构造Huffman编码。将字母表里的所有字符按优先队列的形式组织起来,每次从中取两个最低频的字符并将其组合成一个新的字符(新字符的频率为两者之和),然后再将新字符插入队列中。如此这般,我们便可以构造出编码树。
如果你无法理解,请查阅《算法导论》的6.3节。这里附上了相关证明:

接下来我们来实现一个简单的HuffComp和HuffUnComp。
如果我们要解码一段用Huffman编码压缩的数据,那么我们必须得获取相应的编码树。这里详细讲讲如何存储编码树。
为了节省空间,如果一个字符从来没有出现过,那么我们就不把它放入编码树。
在最前面,我们用一个字节来表示编码树的尺寸,以便定位编码的数据区。此外,我们用一个字节来存储一个结点。其中,最高位表示左孩子是叶结点,次高位表示右孩子是叶结点,低6位表示孩子结点的偏移。
不难发现,这种存储方式由于偏移十分有限,可能无法存储一棵有着256个叶结点的树,所以在这种情况下,我们需要使用16个叶子结点的树。该采用何者由压缩头attr的低4位指定。
基于上述说明,我们可以很容易地写出以下代码:
解压缩函数

压缩函数

Huffman编码的思路也非常容易理解,就是采用变长编码,减少高频字符的码长,增加低频字符的码长。
Huffman编码是一种前缀码(即没有任何码字是其他码字的前缀)。与任何字符编码相比,前缀码可以保证达到最优数据压缩率,并简化解码过程。
我们这样构造Huffman编码。将字母表里的所有字符按优先队列的形式组织起来,每次从中取两个最低频的字符并将其组合成一个新的字符(新字符的频率为两者之和),然后再将新字符插入队列中。如此这般,我们便可以构造出编码树。
如果你无法理解,请查阅《算法导论》的6.3节。这里附上了相关证明:

接下来我们来实现一个简单的HuffComp和HuffUnComp。
如果我们要解码一段用Huffman编码压缩的数据,那么我们必须得获取相应的编码树。这里详细讲讲如何存储编码树。
为了节省空间,如果一个字符从来没有出现过,那么我们就不把它放入编码树。
在最前面,我们用一个字节来表示编码树的尺寸,以便定位编码的数据区。此外,我们用一个字节来存储一个结点。其中,最高位表示左孩子是叶结点,次高位表示右孩子是叶结点,低6位表示孩子结点的偏移。
不难发现,这种存储方式由于偏移十分有限,可能无法存储一棵有着256个叶结点的树,所以在这种情况下,我们需要使用16个叶子结点的树。该采用何者由压缩头attr的低4位指定。
基于上述说明,我们可以很容易地写出以下代码:
解压缩函数

压缩函数
