算法快學筆記(七):赫夫曼,赫夫曼樹,赫夫曼編碼

1. 赫夫曼

鼎鼎大名赫夫曼樹以及赫夫曼編碼都是出自赫夫曼這位大牛之手,爲表致敬先簡單的介紹赫夫曼大神。

赫夫曼,全名David Albert Huffman,1925年8月9日-1999年10月7日,生於美國俄亥俄州,計算機科學家,爲霍夫曼編碼的發明者。

1951年,赫夫曼在麻省理工學院(MIT)攻讀博士學位,他爲了完成一篇題爲<<查找最有效的二進制編碼>>的報告,研究出了赫夫曼樹。

1952年,於論文《一種構建極小多餘編碼的方法》(A Method for the Construction of Minimum-Redundancy Codes)中發表了赫夫曼編碼。

2. 赫夫曼樹

哈夫曼樹也叫最優二叉樹(哈夫曼樹),是赫夫曼編碼的理論基礎,目前經常使用到的壓縮和解壓縮技術都是基於赫夫曼的研究基礎上發展而來。通過一個例子來展開對赫夫曼樹的說明

if a < 60 {
    b = "不及格"
}else if a < 70{
    b = "及格"
}else if a < 80 {
    b = "中等"
}else if a < 90{
    b = "良好"
}else {
    b = "優秀"
}

如上代碼是百分制考試的評分標準。粗略看上面的代碼,貌似沒有什麼問題。但是通常情況來說一個班級的學生成績分佈在及格、中等、良好的相對較多,分佈在優秀和不及格的相對較少。但是上面的代碼,最開始的邏輯是先判斷是否及格,再逐漸向上得到結果。當輸入量很大的時候,算法在效率方面是存在一定問題的。

假設實際中學生在5個等級上成績分佈的概率如下表所示。如果按照上述的代碼邏輯執行,70分以上的成績佔總概率的80%,但是想判斷出一個70分以上的成績至少需要執行3次以上的判斷才能得到結果,顯然是十分不合理的。成績等級的分佈如下:

在這裏插入圖片描述

如果能依照成績概率分佈的規律,如下圖,更改成績等級判斷邏輯,那麼程序判斷的次數將大大較少。

在這裏插入圖片描述

2.1 赫夫曼樹原理

按照上面的兩種邏輯,可以把上述的邏輯分別簡化成下圖的二叉樹結構。其中A表示不及格、B及格、C中等、D良好、E優秀。分支線上的數字表示成績所佔比例數。
在這裏插入圖片描述

2.1.1 相關概念

  1. 路徑長度: 從樹中的一個結點到另一個結點之間的分支構成兩個結點之間的路徑,路徑上的分支數目稱作路徑長度。
  2. 樹的路徑長度 : 樹的路徑長度就是從樹根到每一個結點的路徑長度之和。
  3. 赫夫曼樹的定義。若將樹中結點賦給一個有着某種含義的數值,則這個數值稱爲該結點的權。結點的帶權路徑WPL長度爲:從根結點到該結點之間的路徑長度與該結點的權的乘積。給定n個權值作爲n的葉子結點,構造一棵二叉樹,若帶權路徑WPL長度達到最小,稱這樣的二叉樹爲最優二叉樹,也稱爲哈夫曼樹(Huffman Tree)。

關於赫夫曼樹的定義出現了權。如果考慮到帶權的節點,節點的帶權路徑長度爲從該節點到樹根之間的路徑長度與節點上權的乘積。
按照上述所講,則上圖中:

  1. 二叉樹a的WPL = 5 * 1 + 15 * 2 + 40 * 3 + 30 * 4 + 10 * 4 = 315。
  2. 二叉樹b的WPL = 5 * 3 + 15 * 3 + 40 * 2 + 30 * 2 + 10 * 2 = 220。

315和220這兩個結果分別意味着,如果用二叉樹 a 的判斷方法,10000個學生的成績需要做31500次比較,而二叉樹 b 的判斷方法只要做22000次比較。很顯然,二叉樹b的效率比a高了很多。

2.2 赫夫曼構造步驟

看了上述兩個二叉樹的對比,但是想二叉樹 b 這樣的高效的二叉樹又是如何得到的?
步驟如下。

  • 第一步,先把有權值得葉子結點按照從小到大的順序排列成一個有序序列,即爲A5,E10,D10,B15,C70。
  • 第二步,取頭兩個最小權值的結點作爲一個新結點N1的兩個子結點,注意相對較小的的孩子是左孩子,這裏A就是N1的左孩子,D爲N1的右孩子,新結點的權值爲兩個葉子結點的權值之和 5 + 10 = 15;
  • 第三步,將N1替換A與E,插入有序序列中,保持從小到大的排序,即 N1 15,B15,C70;
  • 第四步,重複步驟2,將N1與B作爲一個新結點N2的兩個子結點, N2的權值 = 15 + 15 = 30;

在這裏插入圖片描述

  • 第五步,將N2替換N1與B,插入有序序列中,保持從小到大的排序,即 N2 ,D30,C40;

  • 第六步,重複步驟2,將N2和D作爲一個新結點N3的兩個子結點。N3的權值爲30+30 = 60

  • 第七步,將N3替換N2和D,排序得到C40,N3爲40。

  • 第八步,重複步驟二,將C於N3作爲一個新節點T的兩個子節點。即完成赫夫曼樹的構造。

赫夫曼樹構造完成
在這裏插入圖片描述

最終結果的WPL=40 * 1+30 * 2+15 * 3+10 * 4 * 5=205,比之前的220還少了15.此時的二叉樹纔是最優二叉樹(最優赫夫曼樹)

3. 赫夫曼樹應用之赫夫曼編碼

赫夫曼樹最大的成績是在當前遠距離通訊過程中,解決了數據傳輸最優化問題。比如有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

現在的編碼結果明顯要比之前的少了一些,短短是幾個字母編碼後,少的量不是很大,如果是通篇的文章或更多,那麼編碼量將會節省很多,這就是文件壓縮的原理。並且隨着字符的增多,按照權重優先級編碼,這種壓縮會進一步提升很多。

既然有編碼,就必然有解碼。簡單說說解碼,按照赫夫曼樹這種編碼方法,非0即1,且每個字符編碼長短不等很容易混淆。所以若要設計出長短不等的編碼,則必須是任意字符的編碼都不是另一個字符編碼的前綴(這種編碼通常稱爲前綴編碼)。

自己觀察A=01、B=1001、C=101、D=00、E=11、F=1000根本就不存在容易和 1001 、1000混淆的10和100編碼,這一點從上面的0和1的左右分支圖也能輕易的總結出,因爲ABCDEF這幾個字符都在輸的最末端,所以不會出現這種容易混淆的問題。

最後需要注意的是,是編碼和解碼需要規定好同樣的赫夫曼編碼規則。本例的規則如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章