1 基本概念
①结点路径:从树中一个结点到另一个结点的之间的分支构成这两个结点之间的路径。
②路径长度:结点路径上的分支数目称为路径长度。
③树的路径长度:从树根到每一个结点的路径长度之和。
④结点的带权路径长度:从该结点的到树的根结点之间的路径长度与结点的权(值)的乘积。
权(值):各种开销、代价、频度等的抽象称呼。
⑤ 树的带权路径长度:树中所有叶子结点的带权路径长度之和,记做:
WPL=(i=1,2,⋯,n)其中:n 为叶子结点的个数; 为第 i 个结点的权值; 为第 i 个结点的路径长度。
⑥Huffman 树:具有 n 个叶子结点(每个结点的权值为) 的二叉树不止一棵,但在所有的这些二叉树中,必定存在一棵 WPL 值最小的树,称这棵树为 Huffman 树(或称最优树) 。
在许多判定问题时,利用 Huffman 树可以得到最佳判断算法。权值分别为 2、3、6、7, 具有 4 个叶子结点的二叉树,它们的带权路径长度分别为:
(a) WPL= ;
(b) WPL=
(c) WPL=
其中(c)的 WPL 值最小,可证明是Huffman 树
2 Huffman 树的构造
①根据 n 个权值{},构造成 n 棵二叉树的集合 F={},其中每棵二叉树只有一个权值为 的根结点,没有左、右子树;
②在F中选取两棵根结点权值最小的树作为左、右子树构造一棵新的二叉树,且新
的二叉树根结点权值为其左、右子树根结点的权值之和;
③在F中删除这两棵树,将新得到的树加入F中;
④重复②、③,直到F只含一颗树为止。
规定权值小的二叉树作为新构造的二叉树的左子树,权值大的二叉树作为新构造的二叉树的右子树;
在取值相等时,深度小的二叉树作为新构造的二叉树的左子树,深度大的二叉树作为新构造的二叉树的右子树。
权值集合 W={8, 3, 4, 6, 5, 5}构造 Huffman 树的过程:
3 Huffman 编码
电报收发等数据通讯中,常需要将传送的文字转换成由二进制字符 0、1 组成的字符串来传输。
保证任意字符的编码都不是另一个字符编码的前缀,这种编码称为前缀编码。
Huffman 树可以用来构造编码长度不等且译码不产生二义性的编码。
设电文中的字符集 C={},各个字符出现的次数或频度集 W={}。
Huffman 编码方法:
以字符集 C 作为叶子结点,次数或频度集 W 作为结点的权值来构造 Huffman 树。
规定左分支代表“0”,右分支代表“1” 。
从根结点到每个叶子结点所经历的路径分支上的“0” 或“1”所组成的字符串,为该结点所对应的编码,称之为 Huffman 编码。
由于每个字符都是叶子结点,不可能出现在根结点到其它字符结点的路径上,所以一个字符的 Huffman 编码不可能是另一个字符的 Huffman 编码的前缀。
若字符集 C={a, b, c, d, e, f}所对应的权值集合为 W={8, 3, 4, 6, 5, 5},则字符 a,b, c,d, e,f所对应的 Huffman 编码分别是:10,010,011,00 ,110,111。
4 Huffman 编码算法实现
(1)数据结构设计
Huffman 树中没有度为 1 的结点。
1 棵有 n 个叶子结点的 Huffman 树共有 2n-1 个结点。
可存储在大小为 2n-1 的一维数组中,即 2n-1 =2(n-1)+1。
结点类型定义:
#define MAX_NODE 200
typedef struct {
unsigned int weight; /* 权值域 */
unsigned int parent, lChild, rChild;
} HTNode;
(2)Huffman 树的生成
算法实现
(3) Huffman 编码算法