1. 程式人生 > >資料結構課程設計-哈夫曼樹及其應用

資料結構課程設計-哈夫曼樹及其應用

題目:假設用於通訊的電文由字符集{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?在CODE上檢視程式碼片派生到我的程式碼片
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. //樹結點定義
  5. typedefstruct
  6. {  
  7.     int weight;  
  8.     int parent;  
  9.     int lchild;  
  10.     int rchild;  
  11. }HTNode,*HuffmanTree;  
  12. staticchar N[100];//用於儲存正文
  13. //哈弗曼編碼,char型二級指標
  14. typedefchar **HuffmanCode;  
  15. //封裝最小權結點和次小權結點
  16. typedefstruct
  17. {  
  18.     int s1;  
  19.     int s2;  
  20. }MinCode;  
  21. //函式宣告
  22. void Error(char *message);  
  23. HuffmanCode HuffmanCoding(HuffmanTree &HT,HuffmanCode HC,int *w,int n);  
  24. MinCode   Select(HuffmanTree HT,int n);  
  25. //當輸入1個結點時的錯誤提示
  26. void Error(char *message)  
  27. {    
  28.     fprintf(stderr,"Error:%s\n",message);    
  29.     exit(1);  
  30. }  
  31. //構造哈夫曼樹HT,編碼存放在HC中,w為權值,n為結點個數
  32. HuffmanCode HuffmanCoding(HuffmanTree &HT,HuffmanCode HC,int *w,int n)  
  33. {   
  34.     int i,s1=0,s2=0;   
  35.     HuffmanTree p;  
  36.     char *cd;  
  37.     int f,c,start,m;  
  38.     MinCode min;  
  39.     if(n<=1)   
  40.     {  
  41.         Error("Code too small!");//只有一個結點不進行編碼,直接exit(1)退出。非return,如果return 會造成main函式HT[i]無值
  42.     }  
  43.     m=2*n-1;//哈弗曼編碼需要開闢的結點大小為2n-1
  44.     HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//開闢哈夫曼樹結點空間 m+1 。為了對應關係,我們第0個空間不用。
  45.     //初始化n個葉子結點,w[0] = 0,main函式已賦值
  46.     for(p=HT,i=0;i<=n;i++,p++,w++)  
  47.     {   
  48.         p->weight=*w;    
  49.         p->parent=0;   
  50.         p->lchild=0;   
  51.         p->rchild=0;  
  52.     }  
  53.     //將n-1個非葉子結點的初始化
  54.     for(;i<=m;i++,p++)  
  55.     {   
  56.         p->weight=0;    
  57.         p->parent=0;   
  58.         p->lchild=0;  
  59.         p->rchild=0;  
  60.     }  
  61.     //構造哈夫曼樹
  62.     for(i=n+1;i<=m;i++)  
  63.     {  
  64.         min=Select(HT,i-1);//找出最小和次小的兩個結點
  65.         s1=min.s1 ; //最小結點下標
  66.         s2=min.s2;//次小結點下標
  67.         HT[s1].parent=i;   
  68.         HT[s2].parent=i;  
  69.         HT[i].lchild=s1;  
  70.         HT[i].rchild=s2;  
  71.         HT[i].weight=HT[s1].weight+HT[s2].weight;//賦權和
  72.     }  
  73.     //列印哈弗曼樹
  74.     printf("HT  List:\n");  
  75.     printf("Number\t\tweight\t\tparent\t\tlchild\t\trchild\n");  
  76.     for(i=1;i<=m;i++)  
  77.     {  
  78.         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);  
  79.     }  
  80.     //從葉子結點到根節點求每個字元的哈弗曼編碼
  81.     HC=(HuffmanCode)malloc((n+1)*sizeof(char *));  
  82.     cd=(char *)malloc(n*sizeof(char *));//為哈弗曼編碼動態分配空間
  83.     cd[n-1]='\0';//如:3個結點編碼最長為2。cd[3-1] = '\0';
  84.     //求葉子結點的哈弗曼編碼
  85.     for(i=1;i<=n;i++)  
  86.     {   
  87.         start=n-1;  
  88.         //定義左子樹為0,右子樹為1
  89.         /* 
  90.         從最下面的1號節點開始往頂部編碼(逆序存放),然後編碼2號節點,3號...... 
  91.         */
  92.         for(c=i,f=HT[i].parent; f!=0; c=f,f=HT[f].parent)  
  93.         {  
  94.             if(HT[f].lchild==c)    
  95.                 cd[--start]='0';  
  96.             else
  97.                 cd[--start]='1';  
  98.         }  
  99.         //為第i個字元分配編碼空間
  100.         HC[i]=(char *)malloc((n-start)*sizeof(char *));  
  101.         //將當前求出結點的哈弗曼編碼複製到HC
  102.         strcpy(HC[i],&cd[start]);     
  103.     }  
  104.     free(cd);  
  105.     return HC;  
  106. }  
  107. MinCode Select(HuffmanTree HT,int n)  
  108. {    
  109.     int min,secmin;  
  110.     int temp = 0;  
  111.     int i,s1,s2,tempi = 0;  
  112.     MinCode  code ;  
  113.     s1=1;  
  114.     s2=1;  
  115.     min = 66666;//足夠大
  116.     //找出權值weight最小的結點,下標儲存在s1中
  117.     for(i=1;i<=n;i++)  
  118.     {  
  119.         if(HT[i].weight<min && HT[i].parent==0)  
  120.         {  
  121.             min=HT[i].weight;  
  122.             s1=i;  
  123.         }  
  124.     }  
  125.     secmin = 66666;//足夠大
  126.     //找出權值weight次小的結點,下標儲存在s2中
  127.     for(i=1;i<=n;i++)  
  128.     {  
  129.         if((HT[i].weight<secmin) && (i!=s1) && HT[i].parent==0)  
  130.         {  
  131.             secmin=HT[i].weight;   
  132.             s2=i;  
  133.         }  
  134.     }  
  135.     //放進封裝中
  136.     code.s1=s1;  
  137.     code.s2=s2;  
  138.     return code;  
  139. }  
  140. void HuffmanTranslateCoding(HuffmanTree HT, int n,char