数据结构(十四) -- Huffman树

2016-11-01  本文已影响180人  峰峰小

本文将通过 Huffman 编码树的构造问题,介绍优先队列结构的具体应用。

二进制编码

通讯系统可以帮助人们将一段信息从发送端传送给接收端。最常见的信息形式是字符串,即由来自某一有限字符集Σ 的若干个字符组成的一个序列M = (x1, …, xn),xi∈Σ,1≤i≤n。在将M 加载至信道上并发送之前,首先需要对M 进行编码(Encoding)。通常采用的都是二进制编码,以英文字母集Σ = {A, B, C, …, Z}为例,若需要传送字符串“MAIN”,一种可行的编码方式就是:

e('N') = "00"
e('A') = "010"
e('I') = "011"
e('M') = "1"

若令每个字符分别对应于一匹叶子,则从根节点通往每匹叶子的路径,就对应于相应字符的二进制编码,这样的一棵树也称作二叉编码树。

二进制解码

反过来,根据这棵编码树也可以便捷地完成解码工作。

实际上,这一过程可以在接收过程中实时进行,而不必等到所有的比特位都到达之后才开始解码。

最优编码树

在实际的通讯系统中,信道的使用效率是个很重要的问题,这在很大程度上取决于编码算法本身的效率。很自然地,我们当然希望能够用尽可能少的比特位来表示字符串。那么,如何做到这一点呢?在什么情况下能够做到这一点呢?

先介绍一项编码效率的重要指标——平均编码长度

在二叉编码树中每个字符 c 的编码长度为对应的叶子的深度 depth(c)。

Σ 中各字符的编码长度总和除以字符集 Σ 就是单个字符的平均编码长度。

对于任一字符集Σ,若在所有的编码方式中,某一编码方式 e() 使得平均编码长度最短,则称 e() 为 Σ 的一种最优编码,与之对应的编码树称作 Σ 的一棵最优编码树。

我们注意到,对于同一字符集Σ,所有深度不超过|Σ|的编码树只有有限棵,因此其中的总编码长度最小者必然存在(尽管不见得唯一)。

如何找到最优编码树

首先需要更加深入地了解最优编码树的性质,在最优二叉编码树中:

推论:基于由 2 | Σ | -1 个节点构成的完全二叉树 T,将 Σ 中的字符任意分配给 T 的 | Σ | 匹叶子,即可得到 Σ 的一棵最优编码树。

这一推论也直接给出了一个构造最优编码树的算法。

带权编码

上面所介绍的最优编码树,在实际应用中的利用价值并不大。不难看出,只有当 Σ 中各个字符在信息串中出现的概率相等时,其最优性才有意义,遗憾的是,这一条件很难满足。

在实际应用中,Σ 中各字符的出现频率不仅很少相等或相近,而且往往相差悬殊。以英文信息串为例,'e'、't'等字符的出现频率通常都是'z'、'j'等字符的数百倍。在这种情况下,就应该从另一角度衡量每个字符的编码长度。

若假设字符 c 出现的概率为 p(c) ≥ 0, 其在二叉编码树中对应的叶子的深度记作depth(c),则:

例如:信息串" M A M A N I "

各字符出现的概率分别为p('M') = 2/6、p('A') = 2/6、p('I') = 1/6 和p('N') = 1/6

则各字符的带权编码长度分别为:
|e('M')| = 3×(2/6) = 1
|e('A')| = 3×(2/6) = 1
|e('I')| = 2×(1/6) = 1/3
|e('N')| = 1×(1/6) = 1/6

相应地,这一编码方式对应的平均带权编码长度就是:
|e('M')| + |e('A')| + |e('I')| + |e('N')| = 2.5

如何找到最优带权编码树(不唯一)

首先

** 完全二叉编码树 ≠ 平均带权编码最短 **

最优带权编码树有以下性质:

对于字符出现概率满足一定分布的任一字符集 Σ ,我们都可以按照如下算法来构造其对应的 Huffman 编码树:

首先,对应于 Σ 中的每一字符,分别建立一棵由单个节点组成树,其权重就是该字符出现的频率,这|Σ |棵树组成一个森林 F。

接下来,从 F 中选出权重最小的两棵树,创建一个新节点,并分别以这两棵树作为其左、右子树,从而将它们合成为一棵更高的树,其权重等于其左、右子树权重之和。

这一选取、合并的过程将反复进行,直到最后 F 中只剩下一棵树⎯⎯它就是我们所需要的 Huffman 编码树。

举个例子:

字符 出现频率
A 623
B 99
C 239
D 290
E 906
F 224
基于优先队列的 Huffman 树构造算法

具体方法是:

因此,经过 n-1 次迭代,森林中将只包含一棵树,即 Huffman 编码树。

上一篇下一篇

猜你喜欢

热点阅读