1、背景知识
1、路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
4、哈夫曼树
若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
2、哈夫曼算法
为了构造权值集合为{w1, w2, …, wn}的哈夫曼树,哈夫曼提出了一个构造算法,这个算法就是哈夫曼算法。基本思路如下:
(1)根据给定的n个权值{w1, w2, …, wn},构造具有n棵扩充二叉树的森林F = {T1, T2, T3, …, Tn},其中每棵扩充二叉树Ti只有一个带权值wi的根结点,其左右子树均为空。
(2)重复以下步骤,直到F中只剩下一棵树为止。
①在F中选取两棵根结点的权值最小的子树分别作为左右子树构造一棵新的二叉树。置新的二叉树的根结点的权值为其左右子树上根结点权值之和。
②在F中删去这两棵二叉树。
③把新的二叉树加入F。
最后得到的就是哈夫曼树。
下图是哈夫曼树构造的图解过程:
注:从哈夫曼算法可知,实际上构造出来的哈夫曼树可以不止一棵。
3、哈夫曼树的结点表示
这里用C++中的结构类型描述哈夫曼树中的结点
template<typename T>
struct HTNode
{
T data; //结点值
double weight; //权值
int parent; //双亲结点
int rchild, lchild; //左右孩子结点
};
此处将lchild、rchild、parent依旧称为”指针”,他们实际上是三个整形指示器,分别指示结点在数组中的下标。因为C++语言数组的下界是0,故用-1来表示空指针。设置 parent 域有两个作用,其一是便于查找某个结点的双亲,其二是可通过判断parent的值是否为-1来区分根结点和非根结点。
4、算法实现
哈夫曼算法的初