#include <stdio.h> #include <string.h> #define N 50 //叶子结点数 #define M 2*N-1 //树中结点总数 typedef struct//哈夫曼树的节点 { char data[5]; //结点存储的单词 int weight; //权重(该单词出现次数) int parent; //双亲结点 int lchild; //左孩子结点 int rchild; //右孩子结点 } HTNode; typedef struct//哈夫曼编码 { char cd[N]; //叶子节点对应的哈夫曼编码 int start; //指向哈夫曼编码cd[]的最开始字符(从下标start开始到n为有效的哈夫曼编码) } HCode; void CreateHT(HTNode ht[],int n);//构造 void CreateHCode(HTNode ht[],HCode hcd[],int n);//编码 void DispHCode(HTNode ht[],HCode hcd[],int n);//输出编码 void main() { int n=15;//15个单词(叶节点) ////初始化 char *str[]={"The","of","a","to","and","in","that","he","is","at","on","for","His","are","be"}; int fnum[]={1192,677,541,518,462,450,242,195,190,181,174,157,138,124,123}; HTNode ht[M];//节点 HCode hcd[N];//编码 for (int i=0;i<n;i++) { strcpy(ht[i].data,str[i]); ht[i].weight=fnum[i]; } CreateHT(ht,n);//构造哈夫曼树 CreateHCode(ht,hcd,n);//根据哈夫曼树建立哈夫曼编码 DispHCode(ht,hcd,n);//输出哈夫曼编码 printf("\n"); } void CreateHT(HTNode ht[],int n) { int i,k,lnode,rnode; int min1,min2; for (i=0;i<2*n-1;i++)//ht[]初始化---所有结点的相关域置初值-1 ht[i].parent=ht[i].lchild=ht[i].rchild=-1; //构造哈夫曼树/////////////////////////////// for (i=n;i<2*n-1;i++) { min1=min2=32767;//最小权重和次小权重 lnode=rnode=-1;//最小两个权重位置(节点下标) //从已有的节点且未构造二叉树的节点中选取权重最小的两个节点 for (k=0;k<=i-1;k++)//树中现有i个节点 if (ht[k].parent==-1)//尚未构造二叉树的结点 { if (ht[k].weight<min1)//k号节点权重比最小权重min1还小 { min2=min1;rnode=lnode;//次小权重min2取最小权重min1 min1=ht[k].weight;lnode=k;//最小权重min1取k号节点对应的权重 } else if (ht[k].weight<min2)//k号节点权重大于最小权重,小于次小权重min2 { min2=ht[k].weight;rnode=k;//次小权重min2取k号节点权重 } } ht[lnode].parent=i;ht[rnode].parent=i;//权重最小的两个节点构造以i号节点为父节点的二叉树 //新增i号节点(新增节点没有data域) ht[i].weight=ht[lnode].weight+ht[rnode].weight; ht[i].lchild=lnode;ht[i].rchild=rnode; } } void CreateHCode(HTNode ht[],HCode hcd[],int n) { int i,f,temp; HCode hc; for (i=0;i<n;i++) /*根据哈夫曼树求哈夫曼编码*/ { //////对叶节点i对应单词---进行编码//// hc.start=n;//hc.cd[]中编码存放的起始位置(从start开始到n为编码存储区)(编码下标范围是0~N-1) temp=i;//当前节点c取叶节点i f=ht[temp].parent; while (f!=-1)//当前节点c存在父节点 { if (ht[f].lchild==temp)//当前c节点是其父节点的左孩子节点 hc.cd[hc.start--]='0';//编码 else hc.cd[hc.start--]='1';//当前c节点是其父节点的右孩子节点 temp=f;//取c的父节点为新的当前节点c f=ht[temp].parent;//取当新的当前节点c的父节点f } hc.start++;//(从下标hc.start开始存储到hc.start=n结束)---start指向哈夫曼编码最开始字符 //////////////////////////////////////// hcd[i]=hc;//叶节点i对应单词的哈夫曼编码hc存入编码表hcd[i] } } void DispHCode(HTNode ht[],HCode hcd[],int n)//输出哈夫曼编码 { int i,k; int CodeSum=0,WeightAdd=0; printf("输出哈夫曼编码:\n"); for (i=0;i<n;i++)//对于每个单词(叶节点) { int CountLen=0; printf("%s:\t",ht[i].data);//输出单词 for (k=hcd[i].start;k<=n;k++)//输出单词(叶节点)编码 { printf("%c",hcd[i].cd[k]); CountLen++;//统计i号单词编码长度 } WeightAdd+=ht[i].weight;//统计叶节点权重和(即所有单词总数) CodeSum+=ht[i].weight*CountLen;//得到总的编码量(即所有单词的编码总量) printf("\n"); } printf("平均每个单词的编码长度=%g\n",1.0*CodeSum/WeightAdd);//输出每个单词的编码平均长度 } /* 输出哈夫曼编码: The: 01 of: 101 a: 001 to: 000 and: 1110 in: 1101 that: 11110 he: 11001 is: 11000 at: 10011 on: 10010 for: 10001 His: 10000 are: 111111 be: 111110 平均每个单词的编码长度=3.56208 Press any key to continue */