哈夫曼樹及編碼


介紹哈夫曼編碼之前先介紹一下哈弗曼樹:

哈夫曼樹:哈夫曼樹又稱最優二叉樹,是一種帶權路徑長度最短的二叉樹。所謂樹的帶權路徑長度,就是樹中所有的葉結點的權值乘上其到根結點的路徑長度(若根結點為0層,葉結點到根結點的路徑長度 為葉結點的層數)。樹的帶權路徑長度記為WPL= (W1*L1+W2*L2+W3*L3+...+Wn*Ln) N個權值Wi(i=1,2,...n)構成一棵有N個葉結點的二叉樹,相應的葉結點的路徑長度為Li(i=1,2,...n)。可以證明哈夫曼樹的WPL是最小的

哈夫曼樹的構造:

一、構成初始集合

  對給定的n個權值{W1,W2,W3,...,Wi,...,Wn}構成n棵二叉樹的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉樹Ti中只有一個權值為Wi的根結點,它的左右子樹均為空。(為方便在計算機上實現算法,一般還要求以Ti的權值Wi的升序排列。) 

二、選取左右子樹

  在F中選取兩棵根結點權值最小的樹作為新構造的二叉樹的左右子樹,新二叉樹的根結點的權值為其左右子樹的根結點的權值之和。 

三、刪除左右子樹

  從F中刪除這兩棵樹,並把這棵新的二叉樹同樣以升序排列加入到集合F中。 

四、重復二和三兩步,

重復二和三兩步,直到集合F中只有一棵二叉樹為止。

構造過程如下:

a 有權值為1,2,3,4四棵樹;

b 由於樹1,2的權值處於最小和次最小,所以選中,並合成為一棵樹,小的權值位於左邊;

c 從3,4,(1,2 = 3)三棵樹里面選擇權值最小的和次小的,我們選中3和(1,2)

合成新樹(3,(1,2)= 6);

d 最后選出新樹(4,(3,(1, 2)))

 

哈夫曼樹具體實現

 

需要考慮的問題:

 

1 用什么樣的存儲結構;

 

2 怎么選擇選擇最小和次小權值的樹;

 

3 怎么存放合成的新樹

 

如果我們采用

 

Struct node

 

{

 

Int key;

 

Struct node *l;

 

Struct node *r;

 

}

 

的存儲結構的話,可以采用數組的鏈式結構,並設計標記數組如下:

 

(我們以4個初始樹為例子)

 

標記數組:(有則標記為1,否則為0)

 

Struct node n1

Struct node n1

Struct node n1

Struct node n1

 

存儲數組

 

Struct node n1

Struct node n1

Struct node n1

Struct node n1

 

第一次選擇為1,2樹,合成新樹,我們可以統一放在最小樹的位置上(也可以放在大樹位置上),所以新樹放於樹1 的位置並更新其權值為兩者之和,其狀態為:

 

標記數組:(有則標記為1,否則為0)

 

1

0

1

1

 

存儲數組

 

Struct node n1

Free()

Struct node n1

Struct node n1

 

這樣存儲結構的問題解決了,其實做到這里我們應該比較清楚后面怎么做了,當然選擇出最小值和次小值為比較簡單的算法了。

 

例:設有8個字符{A,B,C,D,E,F,G,H},其概率為{0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11},設其權值用整數表示為 {5,29,7,8,14,23,3,11},其哈夫曼樹如圖1所示。

 

 

實現代碼如下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 struct node 
  5 {
  6     int key;
  7     struct node *l;
  8     struct node *r;
  9 };
 10 typedef struct node *pnode;
 11 int mark[100];
 12 struct node  huffman[100];
 13 void PrintNode(const pnode node)
 14 {
 15     printf("key = %d \n", node->key);
 16 }
 17 void PreOrder(pnode T)
 18 {
 19     if(T)
 20            
 21     {
 22            PrintNode(T);
 23            PreOrder(T->l);
 24                 
 25            PreOrder(T->r);
 26             
 27     }
 28       
 29 }
 30 void Select(int *mark, struct node *huffman, int size, int *choose)  
 31 {
 32      
 33         int i;
 34      
 35         for(i = 0;  i< size;  i++)
 36     {
 37         if(mark[i])
 38         {
 39             choose[0] = i;
 40             i++;
 41             break;
 42         }
 43     }
 44     choose[1] = choose[0];
 45         for(; i < size; i++ 46             { 
 47                          if(mark[i]) 
 48                          { 
 49                                               if(huffman[choose[0]].key >= huffman[i].key) 
 50                                                   { 
 51                                                           choose[1] = choose[0];
 52                                                               choose[0] = i;
 53                                                
 54                                                           
 55  56                                                   else if(huffman[choose[1]].key > huffman[i].key)    choose[1] = i;
 57                                            
 58                                                   
 59  60                              
 61  62  63 void Choose(int *mark, struct node *huffman, int size, int *choose)
 64 {
 65     int i;
 66     int minkey = 0;
 67     int tkey = 0;
 68     int temp = 0;
 69     for(i = 0;  i< size;  i++)
 70     {
 71         if(mark[i])
 72         {
 73             minkey = i;
 74             i++;
 75             break;
 76         }
 77     }
 78     tkey = minkey;
 79     for(;  i< size;  i++)
 80     {
 81         if(mark[i])
 82         {
 83             if(huffman[i].key < huffman[minkey].key)
 84             {
 85                 tkey = minkey;
 86                 minkey = i;
 87             }
 88             if(tkey == minkey)
 89                 tkey = i;
 90             if(huffman[tkey].key > huffman[i].key && i != minkey)
 91             {
 92                 tkey = i;
 93             }
 94         }
 95     }
 96     choose[0] = minkey;
 97     choose[1] = tkey;
 98 }
 99 pnode HuffmanTree(int *mark, struct node *huffman, int size)
100 {
101     int choose[2];
102     int i;
103     pnode mynode;
104      
105     for(i = 0;  i < size-1;  i++)
106     {
107         Select(mark, huffman, size, choose);
108         mynode = (pnode)malloc(sizeof(struct node));
109         mynode->key = huffman[choose[0]].key+huffman[choose[1]].key;//更新key值
110         mynode->l = (pnode)malloc(sizeof(struct node));
111         mynode->l->key = huffman[choose[0]].key;
112         mynode->l->l = huffman[choose[0]].l;
113         mynode->l->r = huffman[choose[0]].r;
114         mynode->r = &huffman[choose[1]];
115         huffman[choose[0]] = *mynode;
116         mark[choose[1]] = 0;
117         free(mynode);
118 119     return &huffman[choose[0]];
120 }
121 int main(void)
122 {
123     int key[8] =  {5,29,7,8,14,23,3,11};
124     int i;
125     pnode huffmantree;
126     memset(mark, -1sizeof(mark));
127     memset(huffman, 0sizeof(huffman));
128     for(i = 0;  i < 8;  i++)
129     {
130         huffman[i].key = key[i];
131     }
132     huffmantree = HuffmanTree(mark, huffman, 8);
133     PreOrder(huffmantree);
134     return 0;
135 }

哈夫曼編碼:

思想:得到哈夫曼樹后,自頂向下按路徑編號,指向左節點的邊編號0,指向右節點的邊編號1,從根到葉節點的所有邊上的0和1連接起來,就是葉子節點中字符的哈夫曼編碼。

下圖體現了哈夫曼編碼的過程:

 

 

 

很晚了==拜拜。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM