先經過一個小例子來引出哈夫曼樹,例:將學生的百分制成績轉換爲五分製成績:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。bash
編制一個程序,將百分制轉換成五個等級輸出if (a < 60){
b = "E";
}
else if (a < 70) {
b = "D";
}
else if (a<80) {
b = "C";
}
else if (a<90){
b = "B";
}
else {
b = "A";
}
複製代碼
若考慮上述程序所耗費的時間,就會發現該程序的缺陷。在實際中,學生成績在五個等級上的分佈是不均勻的。當學生百分制成績的錄入量很大時,上述斷定過程須要反覆調用,
此時程序的執行效率將成爲一個嚴重問題。編碼
上述判斷方式對應的判別樹以下:spa
若是學生的總成績數據有10000條,則5%的數據需 1 次比較,15%的數據需 2 次比較,40%的數據需 3 次比較,40%的數據需 4 次比較所以 10000 個數據比較的 次數爲: 10000 (5%+2×15%+3×40%+4×40%)=31500次
設計
再看另外一種判斷方式:3d
此種形狀的二叉樹,須要的比較次數是:10000 (3×20%+2×80%)=22000次
顯然:兩種判別樹的效率是不同的。code
哈夫曼樹定義:在權爲w1,w2,…,wn的n個葉子結點的全部二叉樹中,帶權路徑長度WPL最小的二叉樹稱爲赫夫曼樹或最優二叉樹。cdn
帶權路徑長度的最優值叫作WPL也就是上述例子的判斷總次數31500次或者22000次 blog
其中,n表示葉子結點的數目,wi和li分別表示葉子結點ki的權值和樹根結點到葉子結點ki之間的路徑長度。 也就是上述例子的wi==這個結果的次數,li==須要判斷的次數。構造規則:string
例:有4 個結點 a, b, c, d,權值分別爲 7, 5, 2, 4,構造哈夫曼樹。it
根據給定的n個權值{w1,w2,…,wn}構成二叉樹集合F={T1,T2,…,Tn}
在F中選取兩棵根結點權值最小的樹做爲左右子樹構造一棵新的二叉樹,且置新的二叉樹的根結點的權值爲左右子樹根結點的權值之和. 在F中刪除這兩棵樹,同時將新的二叉樹加入F中. 重複,直到F只含有一棵樹爲止.(獲得哈夫曼樹)哈夫曼樹的應用很廣,哈夫曼編碼就是應用之一。
例:若是需傳送的電文爲 ‘ABACCDA’,它只用到四種字符,用兩位二進制編碼即可分辨。假設 A, B, C, D 的編碼分別爲 00, 01,10, 11,則上述電文便爲 ‘00010010101100’(共 14 位),譯碼員按兩位進行分組譯碼,即可恢復原來的電文。 這種編碼的特色是譯碼簡單且具備惟一性,但編碼長度並非最短的。
在傳送電文時,爲了使其二進制位數儘量地少,能夠將每一個字符的編碼設計爲不等長的,使用頻度較高的字符分配一個相對比較短的編碼,使用頻度較低的字符分配一個比較長的編碼。例如,能夠爲A,B,C,D四個字符分別分配0,00,1,01,並可將上述電文用二進制序列:000011010發送,其長度只有9個二進制位,但隨之帶來了一個問題,接收方接到這段電文後沒法進行譯碼,由於沒法判定前面4個0是4個A,1個B、2個A,仍是2個B,即譯碼不惟一,所以這種編碼方法不可以使用。
所以,爲了設計長短不等的編碼,以便減小電文的總長,還必須考慮編碼的惟一性,即在創建不等長編碼時必須使任何一個字符的編碼都不是另外一個字符的前綴,這宗編碼稱爲前綴編碼(prefix code)利用哈夫曼樹來實現
以電文中的字符做爲葉子結點構造二叉樹。而後將二叉樹中結點引向其左孩子的分支標 ‘0’,引向其右孩子的分支標 ‘1’
; 每一個字符的編碼即爲從根到每一個葉子的路徑上獲得的 0, 1 序列。如此獲得的即爲二進制前綴編碼。
任意一個葉子結點都不可能在其它葉子結點的路徑中。
好比有ABCDEF六個字母,經過0和1編碼用二進制字符發送。普通編碼後的數據爲000001010011100101
,解碼的時候能夠按照3位一份來解碼。 假設ABCDEF出現的機率分別爲27%、8%、15%、15%、30%、5%。則造成的赫夫曼樹以下圖。此外咱們能夠將左右分支分別改成0和1,而後用0和1來編碼字母。
A=0一、B=100一、C=10一、D=00、E=十一、F=1000。
本來的編碼結果爲:000001010011100101
如今的編碼結果爲: 0110011010011100
複製代碼
如今的編碼結果明顯要比以前的少了一些,短短是幾個字母編碼後,少的量不是很大,若是是通篇的文章或更多,那麼編碼量將會節省不少,這就是文件壓縮的原理。而且隨着字符的增多,按照權重優先級編碼,這種壓縮會進一步提高不少。