实验五 哈夫曼树的创建与哈夫曼编码
一、实验目的
1、掌握哈夫曼树的三叉链表存储结构。
2、掌握利用构造哈夫曼树的算法。
3、掌握利用哈夫曼树进行哈夫曼编码及译码。
二、实验内容
1、假设用于通信的电文仅由a、b、c、d、e、f、g、h几个字母组成,字母在电文中出现的频率分别为0.07、0.19、0.02、0.06、0.32、0.03、0.21和0.10,为这些字母设计哈夫曼编码。
2、用静态三叉链表作为哈夫曼树的存储结构。
三、程序清单
#include <stdlib.h>
#include <stdio.h>
#define N 100//最大数字个数为100
#define MN N*2-1
typedef struct/*静态三叉链的扩展存储,包括数据+权值+父亲、左孩、右孩结点在数组中位置*/
{
char data; /*结点值*/
double weight; /*权重*/
int parent; /*双亲结点*/
int lchild; /*左孩子结点*/
int rchild; /*右孩子结点*/
} HTNode;
typedef struct
{
char cd[N];//存放当前节点的哈夫曼码
int star;//表示cd[star.n0]部分是哈夫曼码
}HCode;
void CreateHT(HTNode ht[],int n0)
{
int i,k,lnode,rnode;
double min1,min2;
for(i=0;i<2*n0-1;i++) //所有结点的相关域值初值为-1
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
for(i=n0;i<=2*n0-2;i++) //构造哈夫曼树的n0-1个分支结点
{
min1=min2=32767; //lnode和rnode为最小权重的两个结点位置
lnode=rnode=-1;
for(k=0;k<=i-1;k++) //在ht[0…i-1]中找权值最小的两个结点
if(ht[k].parent==-1) //只在尚未构造二叉树的结点中查找
{
if(ht[k].weight<min1)
{
min2=min1;rnode=lnode;
min1=ht[k].weight;lnode=k;
}
else if(ht[k].weight<min2)
{
min2=ht[k].weight; rnode=k;
}
}
ht[i].weight=ht[lnode].weight+ht[rnode].weight;
ht[i].lchild=lnode;
ht[i].rchild=rnode; //[i]作为双亲结点
ht[lnode].parent=i;
ht[rnode].parent=i;
}
}
void CreateHCode(HTNode ht[],HCode hcd[],int n0)
{
int i,f,c;
HCode hc;
for(i=0;i<n0;i++){
hc.star=n0;
c=i;
f=ht[i].parent;
while(f!=-1){
if(ht[f].lchild==c)
hc.cd[hc.star--]='0';
else
hc.cd[hc.star--]='1';
c=f;
f=ht[f].parent;
}
hc.star++;
hcd[i]=hc;
}
}
int main()
{
HTNode ht[N]; /* 定义一个结点结构体数组 */
HCode hcd[MN],cd; /* 定义一个编码结构体数组, 同时定义一个临时变量来存放求解编码时的信息 */
int j,n,length=0;
double wpl=0,a=0;
printf ("请输入编码个数:\n");
scanf ("%d", &n);
getchar();
printf ("请输入待编码字符(请一次性输入,不加空格回车等):\n");
for(int i = 0;i<n;i++){
scanf("%c",&ht[i]);
}
printf("请输入相应的权值(用空格隔开):\n");
for(int i=0;i< n;i++){
scanf("%lf",&ht[i].weight);
}
CreateHT (ht,n);
CreateHCode(ht,hcd,n);
/* 输出已保存好的所有存在编码的哈夫曼编码 */
printf ("哈夫曼编码为\n");
for (int i=0; i<n; i++)
{
printf("%c:",ht[i]);
for (j=hcd[i].star;j<=n;j++)
{
printf ("%c", hcd[i].cd[j]);
length++;
}
printf("\t长度length:%d",length);
printf ("\n");
a=length*ht[i].weight;
length=0;
wpl+=a;
}
printf("带权路径长度wpl:%lf",wpl);
}
四、代码运行结果
如有错误,请各位不吝指正并多多包涵