数据结构课程设计-哈夫曼树及其应用

题目:假设用于通信的电文由字符集{a,b,c,d,e,f,g,h,}中的字母构成,这8个字母在电文中出现的 频率分别为:

{0.19, 0.21, 0.02, 0.03, 0.06, 0.07, 0.1, 0.32}.

要求:画出哈夫曼树。

我从课本上面摘抄了一个题目,题目大概是上面这样的,我们这里只是详细的说明一下哈弗曼树要怎么构建。借用一下这个题目。


分析:我们这里直接将小数整数化,容易看出大小来。

(1)8个结点的权值大小如下:


(2)从19,21,2,3,6,7,10,32中选择两个权小结点。选中2,3。同时算出这两个结点的和5。


(3)从19,21,6,7,10,32,5中选出两个权小结点。选中5,6。同时计算出它们的和11。


(4)从19,21,7,10,32,11中选出两个权小结点。选中7,10。同时计算出它们的和17。

注:这时选出的两个数字都不是原来的二叉树里面的结点,所以要另外开一棵二叉树。


(5)从19,21,32,11,17中选出两个权小结点。选中11,17。同时计算出它们的和28。


(6)从19,21,32,28中选出两个权小结点。选中19,21。同时计算出它们的和40。  另起一颗二叉树。



(7)从32,28, 40中选出两个权小结点。选中28,32。同时计算出它们的和60。  


(7)从 40, 60中选出两个权小结点。选中40,60。同时计算出它们的和100。 好了,此时哈夫曼树已经构建好了。



ps:上次做作业的时候,我构造哈弗曼树就是一直从剩下的结点里面找权值最小的,然后添加上去,而没有考虑构造出来的"和"权值的大小问题。导致哈夫曼树构造错误!


哈夫曼编码及译码的实现:

[cpp]  view plain  copy
 print ?
  1. #include  
  2. #include  
  3. #include  
  4.   
  5. //树结点定义  
  6. typedef  struct   
  7. {  
  8.     int weight;  
  9.     int parent;  
  10.     int lchild;  
  11.     int rchild;  
  12. }HTNode,*HuffmanTree;  
  13.   
  14. static char N[100];//用于保存正文  
  15.   
  16. //哈弗曼编码,char型二级指针  
  17. typedef char **HuffmanCode;  
  18.   
  19. //封装最小权结点和次小权结点  
  20. typedef  struct   
  21. {  
  22.     int s1;  
  23.     int s2;  
  24. }MinCode;  
  25.   
  26. //函数声明  
  27. void Error(char *message);  
  28. HuffmanCode HuffmanCoding(HuffmanTree &HT,HuffmanCode HC,int *w,int n);  
  29. MinCode   Select(HuffmanTree HT,int n);  
  30.   
  31. //当输入1个结点时的错误提示  
  32. void Error(char *message)  
  33. {    
  34.     fprintf(stderr,"Error:%s\n",message);    
  35.     exit(1);  
  36. }  
  37.   
  38. //构造哈夫曼树HT,编码存放在HC中,w为权值,n为结点个数  
  39. HuffmanCode HuffmanCoding(HuffmanTree &HT,HuffmanCode HC,int *w,int n)  
  40. {   
  41.     int i,s1=0,s2=0;   
  42.     HuffmanTree p;  
  43.     char *cd;  
  44.     int f,c,start,m;  
  45.     MinCode min;  
  46.   
  47.     if(n<=1)   
  48.     {  
  49.         Error("Code too small!");//只有一个结点不进行编码,直接exit(1)退出。非return,如果return 会造成main函数HT[i]无值  
  50.     }  
  51.   
  52.     m=2*n-1;//哈弗曼编码需要开辟的结点大小为2n-1  
  53.     HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//开辟哈夫曼树结点空间 m+1 。为了对应关系,我们第0个空间不用。  
  54.   
  55.     //初始化n个叶子结点,w[0] = 0,main函数已赋值  
  56.     for(p=HT,i=0;i<=n;i++,p++,w++)  
  57.     {   
  58.         p->weight=*w;    
  59.         p->parent=0;   
  60.         p->lchild=0;   
  61.         p->rchild=0;  
  62.     }  
  63.       
  64.     //将n-1个非叶子结点的初始化  
  65.     for(;i<=m;i++,p++)  
  66.     {   
  67.         p->weight=0;    
  68.         p->parent=0;   
  69.         p->lchild=0;  
  70.         p->rchild=0;  
  71.     }  
  72.       
  73.     //构造哈夫曼树  
  74.     for(i=n+1;i<=m;i++)  
  75.     {  
  76.         min=Select(HT,i-1);//找出最小和次小的两个结点  
  77.         s1=min.s1 ; //最小结点下标  
  78.         s2=min.s2;//次小结点下标  
  79.         HT[s1].parent=i;   
  80.         HT[s2].parent=i;  
  81.         HT[i].lchild=s1;  
  82.         HT[i].rchild=s2;  
  83.         HT[i].weight=HT[s1].weight+HT[s2].weight;//赋权和  
  84.     }  
  85.       
  86.     //打印哈弗曼树  
  87.     printf("HT  List:\n");  
  88.     printf("Number\t\tweight\t\tparent\t\tlchild\t\trchild\n");  
  89.       
  90.     for(i=1;i<=m;i++)  
  91.     {  
  92.         printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\t\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);  
  93.     }  
  94.   
  95.     //从叶子结点到根节点求每个字符的哈弗曼编码  
  96.     HC=(HuffmanCode)malloc((n+1)*sizeof(char *));  
  97.     cd=(char *)malloc(n*sizeof(char *));//为哈弗曼编码动态分配空间  
  98.     cd[n-1]='\0';//如:3个结点编码最长为2。cd[3-1] = '\0';  
  99.   
  100.     //求叶子结点的哈弗曼编码  
  101.     for(i=1;i<=n;i++)  
  102.     {   
  103.         start=n-1;  
  104.         //定义左子树为0,右子树为1  
  105.         /* 
  106.         从最下面的1号节点开始往顶部编码(逆序存放),然后编码2号节点,3号...... 
  107.         */  
  108.         for(c=i,f=HT[i].parent; f!=0; c=f,f=HT[f].parent)  
  109.         {  
  110.             if(HT[f].lchild==c)    
  111.                 cd[--start]='0';  
  112.             else   
  113.                 cd[--start]='1';  
  114.         }  
  115.           
  116.         //为第i个字符分配编码空间  
  117.         HC[i]=(char *)malloc((n-start)*sizeof(char *));  
  118.         //将当前求出结点的哈弗曼编码复制到HC  
  119.         strcpy(HC[i],&cd[start]);     
  120.     }  
  121.     free(cd);  
  122.     return HC;  
  123. }  
  124.   
  125. MinCode Select(HuffmanTree HT,int n)  
  126. {    
  127.     int min,secmin;  
  128.     int temp = 0;  
  129.     int i,s1,s2,tempi = 0;  
  130.     MinCode  code ;  
  131.     s1=1;  
  132.     s2=1;  
  133.   
  134.     min = 66666;//足够大  
  135.       
  136.     //找出权值weight最小的结点,下标保存在s1中  
  137.     for(i=1;i<=n;i++)  
  138.     {  
  139.         if(HT[i].weight
  140.         {  
  141.             min=HT[i].weight;  
  142.             s1=i;  
  143.         }  
  144.     }  
  145.   
  146.     secmin = 66666;//足够大  
  147.   
  148.     //找出权值weight次小的结点,下标保存在s2中  
  149.     for(i=1;i<=n;i++)  
  150.     {  
  151.         if((HT[i].weight
  152.         {  
  153.             secmin=HT[i].weight;   
  154.             s2=i;  
  155.         }  
  156.     }  
  157.   
  158.     //放进封装中  
  159.     code.s1=s1;  
  160.     code.s2=s2;  
  161.     return code;  
  162. }  
  163.   
  164. void HuffmanTranslateCoding(HuffmanTree HT, int n,char* ch)  
  165. {//译码过程  
  166.     int m=2*n-1;  
  167.     int i,j=0;  
  168.       
  169.     printf("After Translation:");  
  170.     while(ch[j]!='\0')//ch[]:你输入的要译码的0101010串  
  171.     {  
  172.         i=m;  
  173.         while(0 != HT[i].lchild && 0 != HT[i].rchild)//从顶部找到最下面  
  174.         {  
  175.             if('0' == ch[j])//0 往左子树走  
  176.             {  
  177.                 i=HT[i].lchild;  
  178.             }  
  179.             else//1 往右子树走  
  180.             {  
  181.                 i=HT[i].rchild;  
  182.             }  
  183.             ++j;//下一个路径  
  184.         }  
  185.         printf("%c",N[i-1]);//打印出来  
  186.     }  
  187.     printf("\n");  
  188. }  
  189.   
  190. void main()  
  191. {  
  192.     HuffmanTree HT=NULL;  
  193.     HuffmanCode HC=NULL;  
  194.     int *w=NULL;  
  195.     int i,n;  
  196.     char tran[100];  
  197.       
  198.     printf("Input  N(char):");  
  199.     gets(N);  
  200.     fflush(stdin);  
  201.     n = strlen(N);  
  202.       
  203.     w=(int *)malloc((n+1)*sizeof(int *));//开辟n+1个长度的int指针空间  
  204.     w[0]=0;  
  205.     printf("Enter weight:\n");  
  206.   
  207.     //输入结点权值  
  208.     for(i=1;i<=n;i++)  
  209.     {    
  210.         printf("w[%d]=",i);    
  211.         scanf("%d",&w[i]);  
  212.     }  
  213.     fflush(stdin);  
  214.     //构造哈夫曼树HT,编码存放在HC中,w为权值,n为结点个数  
  215.     HC=HuffmanCoding(HT,HC,w,n);  
  216.   
  217.     //输出哈弗曼编码  
  218.     printf("HuffmanCode:\n");  
  219.     printf("Number\t\tWeight\t\tCode\n");  
  220.     for(i=1;i<=n;i++)  
  221.     {  
  222.         printf("%c\t\t%d\t\t%s\n",N[i-1],w[i],HC[i]);  
  223.     }  
  224.   
  225.     fflush(stdin);  
  226.     //译码过程  
  227.     printf("Input HuffmanTranslateCoding:");  
  228.     gets(tran);  
  229.     HuffmanTranslateCoding(HT, n, tran);  
  230.     return;  
  231. }  

我们对正文:computer进行哈夫曼编码。权值就用上面的那8个好了。

>>computer

>>19

>>21

>>2

>>3

>>6

>>7

>>10

>>32


运行界面、编码结果及译码结果:



你可能感兴趣的:(数据结构)