首先是哈夫曼樹的定義:在一棵二叉樹中,帶權路徑長度達到最小,成這樣的樹是最優二叉樹,也是哈弗曼樹。大概意思就是把數值大的節點放在樹上面,數值小的節點放在樹下面。哈夫曼樹的結構使用順序結構,這裏直接使用了數組。數組
建造哈弗曼樹的思路:根據二叉樹的性質,有n個葉子節點,二叉樹就會有2n-1個節點。定義一個數組,前n個節點做爲葉子節點,從前n個節點中選擇兩個最小的節點,做爲一棵二叉樹的左右節點,這棵二叉樹的根節點值爲左右孩子節點值之和。把這個根節點的值放入數組中,而後接着從數組中(新加入的節點也算)選取兩個最小的節點,只不過把已經使用過的節點忽略掉,這樣不斷循環,每一個節點和其餘節點都有對應關係。編碼
代碼實現:spa
定義結構體,裏面有四個成員,分別爲權值,父節點,左孩子節點,右孩子節點,這裏的節點指的是他在數組中對應的下標位置,若是是0則沒有父節點或者孩子節點,權值不能爲0.code
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 }
哈弗曼編碼:使出現頻率高的編碼放在上面,頻率低的編碼放在下面。blog
以上圖爲例,其中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 }