查了好久信息,五花八门,这一题需要注意筛选出两个权值最小的结点后,将位序最小的放在左子树上,位序次小的放在右子树上。
题目描述
在通讯领域,经常需要将需要传送的文字转换成由二进制字符组成的字符串。在实际应用中,由于总是希望被传送的内容总长尽可能的短,如果对每个字符设计长度不等的编码,且让内容中出现次数较多的字符采用尽可能短的编码,则整个内容的总长便可以减少。另外,需要保证任何一个字符的编码都不是另一个字符的编码前缀,这种编码成为前缀编码。
而赫夫曼编码就是一种二进制前缀编码,其从叶子到根(自底向上)逆向求出每个字符的算法可以表示如下:
在本题中,读入n个字符所对应的权值,生成赫夫曼编码,并依次输出计算出的每一个赫夫曼编码。
输入格式
输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。
第二行中有n个用空格隔开的正整数,分别表示n个字符的权值。
输出格式
共n行,每行一个字符串,表示对应字符的赫夫曼编码。
样例输入
<span style="color:#333333"><span style="color:#333333">8
5 29 7 8 14 23 3 11
</span></span>
样例输出
<span style="color:#333333"><span style="color:#333333">0110
10
1110
1111
110
00
0111
010</span></span>
#include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct HuffmanCode{ int weight; int parent; int lchild; int rchild; }HuffmanCode,*HuffmanTree; void initialHuffmanCode(HuffmanTree,int,int);//初始化结点 void creatHuffmanTree(HuffmanTree,int,int);//构造哈夫曼树 void HuffmanCoding(char**,HuffmanTree,int);//对哈夫曼树进行编码 void TraverseHuffmanCode(char**,int);//自下而上进行遍历 int sum_(HuffmanTree,int);//求哈夫曼树中所有结点权重和 int main(){ int n; scanf("%d",&n); int m=2*n-1;//n个叶子结点共有2*n-1个结点 char **HC=(char**)malloc(n*sizeof(char*));//动态分配内存,可以看成二维数组 HuffmanCode hc[m];//结点 initialHuffmanCode(hc,n,m); creatHuffmanTree(hc,n,m); HuffmanCoding(HC,hc,n); TraverseHuffmanCode(HC,n); } void initialHuffmanCode(HuffmanTree ht,int n,int m){ for(int i=0;i<m;i++){ if(i<n){ scanf("%d",&(ht[i].weight)); } ht[i].parent=-1;//初始化为-1 ht[i].lchild=-1; ht[i].rchild=-1; } } int sum_(HuffmanTree ht,int i){ int sum=0; for(int j=0;j<i;j++){ if(ht[j].parent==-1)//当某结点的已经成为左或右子树时,此结点不参与运算 sum+=ht[j].weight; } return sum; } void creatHuffmanTree(HuffmanTree ht,int n,int m){ int min1,min2;//min1为权重最小,min2为次小 int index1,index2;//index1位序最小,index2位序次小 for(int i=n;i<m;i++){ min1=sum_(ht,i);//每次遍历获得当前哈夫曼树权重 min2=min1; for(int j=0;j<i;j++){//先获得最小权重及下标 if(ht[j].parent==-1){ if(ht[j].weight<min1){ min1=ht[j].weight;// index1=j; } } } ht[index1].parent=i;//双亲结点位序赋值 for(int j=0;j<i;j++){//获得次小权重及下标 if(ht[j].parent==-1){ if(ht[j].weight<min2){ min2=ht[j].weight; index2=j; } } } ht[index2].parent=i; ht[i].weight=min1+min2; if(index1>index2){//需要注意,这里需要比较一下最小和次小的位序!!! int t=index2; index2=index1; index1=t; } ht[i].lchild=index1;//左子树为最小位序,右子树为次小位序 ht[i].rchild=index2; } } void HuffmanCoding(char** HC,HuffmanTree ht,int n){//编码 int child; int parent; int temp; char*p=(char*)malloc((n+1)*sizeof(char));//先给分配一个一维数组(哈夫曼树路径长度我不确定,因此按最大n来算了) p[n]='\0';//结尾添加结束符 for(int i=0;i<n;i++){ temp=n-1; //当前编码字符下标 child=i;//当前孩子下标 parent=ht[child].parent;//双亲下标 while(parent!=-1){ if(ht[parent].lchild==child) p[temp--]='0'; else p[temp--]='1'; child=parent; parent=ht[parent].parent; } HC[i]=(char*)malloc((n-temp)*sizeof(char));//分配n-temp个char字节大小 strcpy(HC[i],p+1+temp);//从p+1+temp开始拷贝 } } void TraverseHuffmanCode(char** HC,int n){//遍历 for(int i=0;i<n;i++){ printf("%s\n",HC[i]); } }