哈夫曼樹概念
先通過一個小例子來引出哈夫曼樹,例:將學生的百分制成績轉換為五分製成績:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。
編制一個程式,將百分制轉換成五個等級輸出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";
}
複製程式碼
若考慮上述程式所耗費的時間,就會發現該程式的缺陷。在實際中,學生成績在五個等級上的分佈是不均勻的。當學生百分制成績的錄入量很大時,上述判定過程需要反覆呼叫,
此時程式的執行效率將成為一個嚴重問題。
上述判斷方式對應的判別樹如下:
如果學生的總成績資料有10000條,則5%的資料需 1 次比較,15%的資料需 2 次比較,40%的資料需 3 次比較,40%的資料需 4 次比較因此 10000 個資料比較的
次數為: 10000 (5%+2×15%+3×40%+4×40%)=31500次
再看另一種判斷方式:
此種形狀的二叉樹,需要的比較次數是:10000 (3×20%+2×80%)=22000次
顯然:兩種判別樹的效率是不一樣的。
哈夫曼樹定義:在權為w1,w2,…,wn的n個葉子結點的所有二叉樹中,帶權路徑長度WPL最小的二叉樹稱為赫夫曼樹或最優二叉樹。
帶權路徑長度的最優值叫做WPL也就是上述例子的判斷總次數31500次或者22000次
其中,n表示葉子結點的數目,wi和li分別表示葉子結點ki的權值和樹根結點到葉子結點ki之間的路徑長度。也就是上述例子的wi==這個結果的次數,li==需要判斷的次數。哈夫曼樹的構造
構造規則:
- 根據給定的n個權值{w1,w2,…,wn}構成二叉樹集合F={T1,T2,…,Tn},其中每棵二叉樹Ti中只有一個帶權為wi的根結點,其左右子樹為空.
- 在F中選取兩棵根結點權值最小的樹作為左右子樹構造一棵新的二叉樹,且置新的二叉樹的根結點的權值為左右子樹根結點的權值之和.
- 在F中刪除這兩棵樹,同時將新的二叉樹加入F中.
- 重複2、3,直到F只含有一棵樹為止.(得到哈夫曼樹)
例:有4 個結點 a, b, c, d,權值分別為 7, 5, 2, 4,構造哈夫曼樹。
根據給定的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=01、B=1001、C=101、D=00、E=11、F=1000。
原本的編碼結果為:000001010011100101
現在的編碼結果為: 0110011010011100
複製程式碼
現在的編碼結果明顯要比之前的少了一些,短短是幾個字母編碼後,少的量不是很大,如果是通篇的文章或更多,那麼編碼量將會節省很多,這就是檔案壓縮的原理。並且隨著字元的增多,按照權重優先順序編碼,這種壓縮會進一步提升很多。