哈夫曼树的应用,算法与实现

一、哈夫曼树是由n个带权叶子结点构成的所有二叉树中带权路径长度最短的二叉树。因该种树最早由哈夫曼(Huffman)研究,所以称为哈夫曼树。

①初始化:用给定的n个权值构成n棵二叉树并构成的森林,每棵二叉树都只有一个权值为wi的根结点,其左右子树为空;
②找最小树:在森林F中选择两棵根结点最小的二叉树,作为一个新二叉树的左、右子树,标记新二叉树的根结点权值为其左、右子树的根结点权值之和。
③删除与加入:从F中删除被选中的那两棵二叉树,同时把新构成的二叉树加入到森林F中
④判断:重复②、③操作,直到森林中只有一棵二叉树为止,此时得到的即为哈夫曼树。
权值越小的距离根结点越远,所以计算带权路径长度是就会具有最小路径长度。
二、存储结构
由于哈夫曼树种没有度为一的结点,所以一棵有n个叶子结点的哈夫曼树共有2n-1个结点(注:因为n0=n2+1),可以用一个大小为2n-1的一维数组来存放哈夫曼树的各个结点。由于每个结点包含其双亲信息和孩子信息,所以构成一个静态三叉链表,各结点存储在一维数组中,0号单元不使用,从1号位置开始使用。
对于有n个叶子结点的哈夫曼树,结点总数为2n-1,为实现方便,将叶子结点集中存储在前面部分1到n个位置,后面的n-1个位置存储其余非叶子结点,并非顺序存储结构。
三、哈夫曼树的类型定义
#define N 20//叶子结点的最大值
#define M 2*N-1//所有结点最大值
typedef struct{
int weight; //结点的权值
int parent; //双亲的下标
int LChild; //左孩子结点的下标
int Rchild; //右孩子结点的下标
}HTNode,HuffmanTree[M+1];//HuffmanTree是一个结构体数组类型,0号单元不用。
四、哈夫曼树的选择算法,选择两棵根结点权值最小的二叉树,作为一棵新二叉树的左右子树。
void select(HuffmanTree ht,int x,int *m,int *n)
{
int i,t,q,p;
t=100;//令t为一个较大的值,便于选出最小的权值,t必须大于所有节点的权值
/*改进算法为:for(i=1;i<=x;i++)
{
if(ht[i].parent!=0) continue;
t=ht[i].weight;
break;
}选出一个parent为0的结点的weight作为t的值。*/

for(i=1;i<=x;i++)
{
    if(ht[i].parent!=0) continue;//如果该叶子节点已经用过则结束此次循环 
    if(ht[i].weight<=t) 
    {
         t=ht[i].weight;
         q=i;
    }
}
*m=q;
t=100;
for(i=1;i<=x;i++)
{
    if(ht[i].parent!=0||i==q) continue;//当i==q时结束此次循环,意在选出除去刚才选出的结点外最小的结点 。 
    if(ht[i].weight<=t) 
    {
         t=ht[i].weight;
         p=i;
    }
}
*n=p;

}
五、创建哈夫曼树算法
void CreHuffmanTree(HuffmanTree ht,int w[],int n)
//构造哈弗曼树ht[M+1],w[]存放n个权值
{
int m,i,s1,s2;
for(i=1;i<=n;i++)
{
ht[i].weight=w[i];
ht[i].LChild=0;
ht[i].parent=0;
ht[i].Rchild=0;
}//1到n号单元存放叶子结点,初始化
m=2*n-1;
for(i=n+1;i<=m;i++)
{
ht[i].weight=0;
ht[i].LChild=0;
ht[i].parent=0;
ht[i].Rchild=0;
}
//n+1到m号单元存放非叶子结点,初始化
for(i=n+1;i<=m;i++)
{
select(ht,i-1,&s1,&s2);//在ht[1]到ht[i-1]的范围内选择两个parent为0且weihgt最小的结点,其序号分别赋值给s1、s2
ht[i].weight=ht[s1].weight+ht[s2].weight;
ht[s1].parent=i;
ht[s2].parent=i;
ht[i].LChild=s1;
ht[i].Rchild=s2;
}
for(i=1;i<=m;i++) printf(“%d %d %d %d\n”,ht[i].weight,ht[i].parent,ht[i].LChild,ht[i].Rchild);//打印出哈夫曼树的终态 ,验证程序的正确性。
}
六、主函数
int main()
{
HuffmanTree ht;
int w[6],n,i;
printf(“请输入叶子结点个数:\n”);
scanf(“%d”,&n);
printf(“请输入权值:\n”);
for(i=1;i<=n;i++) scanf(“%d”,&w[i]);
CreHuffmanTree(ht,w,n);
return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42861049/article/details/81429067