halfman! halfman! 半人萬歲!(來自權力的遊戲 tyrion lannister)
huffman coding哈夫曼編碼的核心是構造哈夫曼樹─即最優二叉樹,帶權路徑長度最小的二叉樹。它會使出現概率高的字元使用較短的編碼,反之出現概率低的則使用較長的編碼,這便使編碼之後的字串的平均期望長度降低,可用於資料的無損耗壓縮。
引入如果對多個字元進行哈夫曼編碼,如 a(7),b(5),c(2),d(4)四個字元進行編碼,其中括號中為該字元平均出現次數,稱為權重,就要將四個字元結點作為葉子結點構造一棵二叉樹,當這棵二叉樹的帶權路徑長度最小時,最優二叉樹就形成了。
結點的路徑長度:該結點到根結點之間的分支數目
結點的帶權路徑長度:結點的路徑長度與權重的乘積
樹的帶權路徑長度:所有結點的帶權路徑長度之和
上圖為一棵最優二叉樹,結點的權值越大,越靠近根結點。該哈夫曼樹的帶權路徑長度wpl為:7+5x2+2x3+4x3=35
它的哈夫曼編碼為:
a: 0 b: 10 c: 110 d: 111演算法實現
哈夫曼樹結點中的parent指標指向父節點的下標編號。
typedef
struct htnode
htnode,
*huffmantree;
哈夫曼編碼儲存在二維字元陣列中,二維陣列的每一行對應乙個字元的編碼,如下:
typedef
char
** huffmancode;
實現哈夫曼編碼的函式如下:其中儲存哈夫曼結點的ht和儲存哈夫曼編碼的hc均為引用,呼叫的select()函式找出一些結點中權重最小的兩個結點來建立合適的新節點,並且有目的使最終演算法實現的哈夫曼樹左邊結點權重總是小於右邊結點的。
void
huffmancoding
(huffmantree& ht, huffmancode& hc,
int* weigh,
char
* character,
int n)
//weigh陣列儲存字元的權值,character陣列儲存字元,n表示字元個數
while
(i < m)
//進行非葉子結點構造,建成哈夫曼樹
//哈夫曼樹構造完畢
hc =
newchar
*[n]
;char
* cd =
newchar
[n];
//備用字元陣列,從後往前輸入資料
cd[n -1]
='\0'
;for
(i =
0; i
) hc[i]
=new
char
[n - start]
;//為第i個字元建立儲存空間
c =0;
while
(start < n)
hc[i]
[c++
]= cd[start++];
//將cd中的字元複製到該字元的哈夫曼編碼儲存結構中
}delete
cd;}
解碼過程實現void
decoding
(huffmantree ht,
int m,
char
* buff)
//buff中為0,1組成的字串
}}
完整示例
這邊列出了乙個完整的範例,是對給定的8個字元進行編碼,輸入字元儲存在data陣列中,相應的權值儲存在weigh陣列中,編碼之後進行解碼。**如下:其中包含編碼輸出結果和解碼結果
#include
#define n 8
typedef
struct htnode
htnode,
*huffmantree;
typedef
char
** huffmancode;
void
huffmancoding
(huffmantree& ht, huffmancode& hc,
int* weigh,
char
* character,
int n)
;//構建哈夫曼樹及哈夫曼編碼
void
select
(huffmantree& a,
int b,
int& s1,
int& s2)
;//查詢下標b之前的兩個最小值
void
decoding
(huffmantree ht,
int m,
char
* buff)
;//哈夫曼編碼的解碼過程
intmain()
;int weigh[n]=;
huffmantree ht;
huffmancode hc;
huffmancoding
(ht, hc, weigh, data, n)
; cout <<
"哈夫曼編碼:"
<< endl;
int count;
for(
int i =
0; i < n; i++
) cout <<
"哈夫曼解碼: "
<< endl;
//char* code = "0110001";//選用f,e,d的哈夫曼編碼
const
char
* c =
"0110001"
;//適用於vs2017版本
int len =
strlen
(c);
char
* code =
newchar
[len+1]
; code[len]
='\0'
;for
(int i =
0; i < len;
++i)
code[i]
= c[i]
;decoding
(ht,
2* n -
1, code)
; cout << endl;
return0;
}void
huffmancoding
(huffmantree& ht, huffmancode& hc,
int* weigh,
char
* character,
int n)
//weigh陣列儲存字元的權值,character陣列儲存字元,n表示字元個數
while
(i < m)
//進行非葉子結點構造,建成哈夫曼樹
//哈夫曼樹構造完畢
hc =
newchar
*[n]
;char
* cd =
newchar
[n];
//備用字元陣列,從後往前輸入資料
cd[n -1]
='\0'
;for
(i =
0; i
) hc[i]
=new
char
[n - start]
;//為第i個字元建立儲存空間
c =0;
while
(start < n)
hc[i]
[c++
]= cd[start++];
//將cd中的字元複製到該字元的哈夫曼編碼儲存結構中
}delete
cd;}void
select
(huffmantree& a,
int b,
int& s1,
int& s2)}}
for(i =
0; i <= b; i++)}
}}void
decoding
(huffmantree ht,
int m,
char
* buff)
//buff中為0,1組成的字串
}}
演算法中所建成的哈夫曼樹如圖:
哎呀,忘了在圖上標註權值了@_@
輸出結果為:
哈夫曼樹(最優二叉樹)
給定n個權值作為n的 葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小 所謂樹的帶權路徑長度,就是樹中所有的葉結點 的權值乘上其到根結點的路徑長度 稱這樣的二叉樹為最優二叉樹,也稱為哈夫曼樹 huffman tree 哈夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。假設有n個權值,則構造出的...
哈夫曼樹(最優二叉樹)
最優二叉樹 哈夫曼樹 給定n個權值,試構造一棵有n個葉子結點的二叉樹,每個葉子結點帶權為wi。構造出來的二叉樹的形態可以有多個,我們把其中帶權路徑長度wpl最小的二叉樹稱作最優二叉樹或者哈夫曼樹。語言描述 根據給定的n個權值構成n棵二叉樹的集合f 其中每棵二叉樹ti中只有乙個帶權為wi的根結點,其左...
哈夫曼樹 最優二叉樹
差點忘記寫部落格了.哈夫曼樹 其實就是只利用葉子結點來儲存要用資訊的樹,只不過它在構造的時候就擁有了乙個迷人的特性.就是wpl 帶權路徑長度 是最小的.而且還能用這個樹的來為葉子結點中的資訊進行編碼,得出來的各個編碼一定不會相同,並且不會產生混淆的情況.通過哈夫曼樹的特點.實現了根據乙個佇列來建立一...