哈夫曼樹及其編碼

首先是哈夫曼樹的定義:在一棵二叉樹中,帶權路徑長度達到最小,成這樣的樹是最優二叉樹,也是哈弗曼樹。大概意思就是把數值大的節點放在樹上面,數值小的節點放在樹下面。哈夫曼樹的結構使用順序結構,這裏直接使用了數組。

建造哈弗曼樹的思路:根據二叉樹的性質,有n個葉子節點,二叉樹就會有2n-1個節點。定義一個數組,前n個節點作爲葉子節點,從前n個節點中選擇兩個最小的節點,作爲一棵二叉樹的左右節點,這棵二叉樹的根節點值爲左右孩子節點值之和。把這個根節點的值放入數組中,然後接着從數組中(新加入的節點也算)選取兩個最小的節點,只不過把已經使用過的節點忽略掉,這樣不斷循環,每個節點和其他節點都有對應關係。

代碼實現:

定義結構體,裏面有四個成員,分別爲權值,父節點,左孩子節點,右孩子節點,這裏的節點指的是他在數組中對應的下標位置,如果是0則沒有父節點或者孩子節點,權值不能爲0.

 

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define n 7
 5 #define m 2*n-1
 6 #define maxval 100
 7 
 8 typedef struct{
 9     int weight;
10     int parent,lchild,rchild;
11 }HufmTree;
12 
13 HufmTree *init(){
14     
15     HufmTree *hf = (HufmTree *)malloc(sizeof(HufmTree));
16     if(hf==NULL)
17         return NULL;
18     
19     return hf;
20     
21 }
22 
23 void setHuffmanTree(HufmTree *tree[]){
24     
25     int i,j,p1,p2,s1,s2;
26     for(i=n;i<m;i++){                        //從n位置開始,都是兩個節點新合成的節點,直到m位置結束 
27         p1 = p2 = 0;                         //每次循環開始,都要數組從頭開始遍歷 
28         s1 = s2 = maxval;                    
29         for(j=0;j<=i-1;j++)                    //在所有節點中尋找,i後面沒有數值的空位置用不到 
30             if(tree[j]->parent==0)             //此處的代碼的作用是檢查該節點是否已經使用過,因爲使用過的節點肯定有父節點    
31                 if(tree[j]->weight<s1){        //尋找最小權值的節點 
32                     s2 = s1;                    
33                     s1 = tree[j]->weight;
34                     p2 = p1;
35                     p1 = j;
36                 }
37                 else if(tree[j]->weight<s2){//尋找次小權值的節點 
38                     s2 = tree[j]->weight;
39                     p2 = j;
40                 }
41         tree[p1]->parent = tree[p2]->parent = i;    //把兩個最小節點的父節點指向i 
42         tree[i]->weight = tree[p1]->weight + tree[p2]->weight;    //父節點權值等於左右孩子權值之和 
43         tree[i]->lchild = p1;                //指明父節點的左右孩子節點 
44         tree[i]->rchild = p2;
45     }
46     
47 }
48 
49 void display(HufmTree *tree[n]){
50     
51     int i;
52     for(i=0;i<m;i++){
53         printf("%d ",tree[i]->weight);
54     }
55     printf("\n");
56 }

 

哈弗曼編碼:使出現頻率高的編碼放在上面,頻率低的編碼放在下面。

 

 

以上圖爲例,其中A的頻率最高,離根節點最近,GFED頻率最低,在最下面。

實現原理:從根節點到每個葉子節點間的路徑值作爲編碼,圖片裏的規定是左子樹的路徑爲1,右子樹的路徑爲0,這樣每個節點都有自己的編碼且不會重複

 1 void createHuffmanCode(HufmTree *tree[n]){
 2      
 3      
 4      int i,j,p,start;
 5      char *temp;                                    //臨時存放字母編碼的數組 
 6      for(i=0;i<n;i++){                            //從0~n之間都是二叉樹的葉子節點 
 7          start = n-1;                            //存放temp數組的下標,從後往前,指向最後面 
 8          temp = (char *)malloc(n*sizeof(char));    //爲數組分配空間 
 9         temp[start] = '\0';                        //添加字符串結束標誌 
10          j = i;                                    //j代表爲哪個葉子節點編碼 
11         p = tree[j]->parent;                    //p是j的父節點 
12          while(p!=0){
13              if(tree[p]->lchild==j)
14                  temp[--start] = '0';            //如果j是p的左孩子,則在數組中添加一個 '0'
15             else
16                 temp[--start] = '1';            //反之則添加一個 '1'
17             j = p;
18             p = tree[p]->parent;                //j和p不斷往上循環 
19         }
20         printf("%d:%s \n",tree[i]->weight,&temp[start]);
21     }
22      
23  }
24  
25 void main(){
26     
27     HufmTree *tree[m];
28     int i,num[n] = {7,3,2,4,9,10,5};
29     
30     //分配空間 
31     for(i=0;i<m;i++)
32         tree[i] = init();
33         
34     //數組每個節點內的所有值初始化時都設爲0 
35     for(i=0;i<m;i++){
36         tree[i]->weight = 0;
37         tree[i]->parent = 0;
38         tree[i]->rchild = 0;
39         tree[i]->lchild = 0;
40     }
41     
42     //爲數組前n個數的權值賦值 
43     for(i=0;i<n;i++)
44         tree[i]->weight = num[i];
45     
46     setHuffmanTree(tree);
47     
48     display(tree);
49     
50     createHuffmanCode(tree);
51     
52 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章