赫夫曼编码
赫夫曼(Huffman)在1952年提出了另一种编码方法,即从下到上的编码方法。现仍以一个具体的例子说明它的编码步骤:
(1) 初始化,根据符号概率的大小按由大到小顺序对符号进行排序,如表4-03和图4-02所示。
(2) 把概率最小的两个符号组成一个节点,如图4-02中的D和E组成节点P1。
(3) 重复步骤2,得到节点P2、P3和P4,形成一棵“树”,其中的P4称为根节点。
(4) 从根节点P4开始到相应于每个符号的“树叶”,从上到下标上“0”(上枝)或者“1”(下枝),至于哪个为“1”哪个为“0”则无关紧要,最后的结果仅仅是分配的代码不同,而代码的平均长度是相同的。
(5) 从根节点P4开始顺着树枝到每个叶子分别写出每个符号的代码,如表4-03所示。
(6) 按照仙农理论,这幅图像的熵为
H(S)=(15/39)×log2(39/15) + (7/39)×log2(39/7) + … + (5/39)×log2(39/5)
=2.1859
压缩比1.37:1。
表4-03 赫夫曼编码举例
符号 出现的次数(pi) log2(1/pi) 分配的代码 需要的位数
A 15(0.3846) 1.38 0 15
B 7(0.1795) 2.48 100 21
C 6(0.1538) 2.70 101 18
D 6(0.1538) 2.70 110 18
E 5(0.1282) 2.96 111 15
图4-02 赫夫曼编码方法
赫夫曼码的码长虽然是可变的,但却不需要另外附加同步代码。例如,码串中的第1位为0,那末肯定是符号A,因为表示其他符号的代码没有一个是以0开始的,因此下一位就表示下一个符号代码的第1位。同样,如果出现“110”,那么它就代表符号D。如果事先编写出一本解释各种代码意义的“词典”,即码簿,那么就可以根据码簿一个码一个码地依次进行译码。
采用赫夫曼编码时有两个问题值得注意:①赫夫曼码没有错误保护功能,在译码时,如果码串中没有错误,那么就能一个接一个地正确译出代码。但如果码串中有错误,哪怕仅仅是1位出现错误,不但这个码本身译错,更糟糕的是一错一大串,全乱了套,这种现象称为错误传播(error propagation)。计算机对这种错误也无能为力,说不出错在哪里,更谈不上去纠正它。②赫夫曼码是可变长度码,因此很难随意查找或调用压缩文件中间的内容,然后再译码,这就需要在存储代码之前加以考虑。尽管如此,赫夫曼码还是得到广泛应用。
与仙农-范诺编码相比,这两种方法都自含同步码,在编码之后的码串中都不须要另外添加标记符号,即在译码时分割符号的特殊代码。此外,赫夫曼编码方法的编码效率比仙农-范诺编码效率高一些。请读者自行验证。