复习目标
学会构造哈夫曼树以及求WPL
知识储备
哈夫曼树的定义以及性质
哈夫曼树又名最优二叉树,指的是当叶子结点带有权值时,通过已知的叶子结点以及相应的权值可以构造出来的带权路径长度最小的二叉树。这就要求权值越大的叶子结点越靠近根结点,而权值越小的叶子结点越远离根结点。
哈夫曼树的基本思想
这里我们用伪代码来进行解释
算法:HuffmanTree
输入:n个权值(a,b,c,d,e...)
输出:哈夫曼树
1.初始化:由(a,b,c,d,e...)构造n棵只有一个结点的二叉树,从而得到一个二叉树集合F={A,B,C,D,E,.....};
2.重复下述操作,直到集合F中只剩下一棵二叉树。
2.1选取与合并:在F中选取根结点的权值最小的两棵二叉树分别作为左子树和右子树从而构造出一棵新的二叉树,新的根结点的权值为其左右孩子的根结点的权值之和。
2.2删除与加入:在F中删除作为左右子树的两棵二叉树,并将新建立的二叉树加入到F中。
哈夫曼树的结点定义如下:
struct ElemType
{
int weight; //假定权值为整数
int parent,lchild,rchild; //游标
};
我们设n个叶子结点的权值保存在数组w[n]中,Select函数用来在数组huffTree中选取两个权值最小的根结点并返回根结点的下标i1和i2,哈夫曼算法的c++描述如下:
void HuffmanTree(ElemType huffTree[],int w[],int n)
{
int i,k,i1,i2;
for (i=0;i<2*n-1;i++) //所有结点均没有双亲和孩子
{
huffTree[i].parent=-1;
huffTree[i].lchild=huffTree[i].rchild=-1;
}
for (i=0;i<n;i++) //存储叶子结点的权值
huffTree[i].weight=w[i];
for (k=n;k<2*n-1;k++) //n-1次合并
{
Select(huffTree,i1,i2); //权值最小的根结点下标为i1,i2
huffTree[k].weight=huffTree[i1].weight+huffTree[i2].weight;
huffTree[i1].parent=k;huffTree[i2].parent=k;
huffTree[k].lchild=i1;huffTree[k].rchild=i2;
}
}
WPL
WPL指的是二叉树的带权路径长度,从根结点到各个叶子结点的路径长度与相应叶子结点的权值的乘积之和。
实际演示
这里演示时,我们使用字符集{a,b,c,d,e,f,g},它们所对应的权值也相应的是{1,2,3,4,5,6,7},请设计出此哈夫曼树。
-
初始化节点集合:
-
节点集合为:
[Node(a, 1), Node(b, 2), Node(c, 3), Node(d, 4), Node(e, 5), Node(f, 6), Node(g, 7)]
-
-
构建哈夫曼树:
-
第一步:选择权值最小的两个节点,即
Node(a, 1)
和Node(b, 2)
,合并它们形成一个新的内部节点,权值为1 + 2 = 3
。-
新节点集合为:
[Node(internal, 3), Node(c, 3), Node(d, 4), Node(e, 5), Node(f, 6), Node(g, 7)]
-
-
第二步:再次选择权值最小的两个节点,即
Node(c, 3)
和新形成的Node(internal, 3)
,合并它们形成一个新的内部节点,权值为3 + 3 = 6
。-
新节点集合为:
[Node(internal, 6), Node(d, 4), Node(e, 5), Node(f, 6), Node(g, 7)]
-
-
第三步:选择权值最小的两个节点,即
Node(d, 4)
和Node(e, 5)
,合并它们形成一个新的内部节点,权值为4 + 5 = 9
。-
新节点集合为:
[Node(internal, 6), Node(internal, 9), Node(f, 6), Node(g, 7)]
-
-
第四步:选择权值最小的两个节点,即
Node(f, 6)
和Node(g, 7)
,合并它们形成一个新的内部节点,权值为6 + 7 = 13
。-
新节点集合为:
[Node(internal, 6), Node(internal, 9), Node(internal, 13)]
-
-
第五步:选择权值最小的两个节点,即
Node(internal, 6)
和Node(internal, 9)
,合并它们形成一个新的内部节点,权值为6 + 9 = 15
。-
新节点集合为:
[Node(internal, 15), Node(internal, 13)]
-
-
第六步:最后,将剩下的两个节点
Node(internal, 15)
和Node(internal, 13)
合并,形成一个根节点,权值为15 + 13 = 28
。
-
-
构建哈夫曼树的结构:
-
根据合并的顺序和结果,我们可以构建出哈夫曼树的具体结构。
-
树的根节点是权值为 28 的内部节点。
-
根节点的左子节点是权值为 15 的内部节点,右子节点是权值为 13 的内部节点。
-
权值为 15 的内部节点的左子节点是权值为 6 的内部节点,右子节点是权值为 9 的内部节点。
-
权值为 6 的内部节点的左子节点是权值为 1 的叶子节点(对应字符 a),右子节点是权值为 2 的叶子节点(对应字符 b)。
-
权值为 9 的内部节点的左子节点是权值为 4 的叶子节点(对应字符 d),右子节点是权值为 5 的叶子节点(对应字符 e)。
-
权值为 13 的内部节点的左子节点是权值为 6 的叶子节点(对应字符 f),右子节点是权值为 7 的叶子节点(对应字符 g)。
-
那么今天的分享就到此为止啦,下次我们会和大家一起学习无向图的邻接矩阵和邻接表以及相应的遍历序列,谢谢大家的阅读。