哈弗曼編碼

2021-09-07 21:36:05 字數 2215 閱讀 6864

|本**遵守cc版權協議

哈弗曼編碼幾乎是所有壓縮演算法的基礎,其實這個演算法並不複雜,簡單的理解就是,如何用更短的bit來編碼資料。     

我們知道普通的編碼都是定長的,比如常用的ascii編碼,每個字元都是8個bit:

字元編碼

a00101001

b00101010

c00101011……

這樣,計算機就能很方便的把由0和1組成的資料流解析成原始資訊,但我們知道,在很多情況下,資料檔案中的字元出現的概率是不均勻的,比如在一篇英語文章中,字母「e」出現的頻率最高,「z」最低,如果我們使用不定長的bit編碼,頻率高的字母用比較短的編碼表示,頻率低的字母用長的編碼表示,豈不是可以大大縮小檔案的空間嗎?     但這就要求編碼要符合「字首編碼」的要求,即較短的編碼不能是任何較長的編碼的字首,這樣解析的時候才不會混淆,比如下面的編碼方法就符合字首原則:

字元編碼a0

b10c110

d1110

e11110……

根據這個碼表,下面一段資料就可以唯一解析成原始資訊了:     1110010101110110111100010 – dabbdceaab

要生成這種編碼,最方便的就是用二叉樹,考察一下下面這個樹

把要編碼的字元放在二叉樹的葉子上,所有的左節點是0,右節點是1,從根瀏覽到葉子上,因為字元只能出現在樹葉上,任何乙個字元的路徑都不會是另一字元路徑的字首路徑,

符合字首原則編碼就可以得到

字元編碼a00

b010

c011d10

e11現在我們可以開始考慮壓縮的問題,如果有一篇只包含這五個字元的文章,而這幾個字元的出現的次數如下:     a: 6次     b : 15次     c: 2次     d : 9次     e: 1次     

用過用定長的編碼,每個字元3bit,這篇文章總長度為:     3*6 + 3*15 + 3*2 + 3*9 + 3*1 = 99    

而用上面用二叉樹生成的編碼,總長度為:     2*6 + 3*15 + 2*2 + 2*9 + 2*1 = 80

顯然,這顆樹還可以進一步優化,使得編碼更短,比如下面的編碼

生成的資料長度為:     3*6 + 1*15 + 4*2 + 2*9 + 4*1 = 63

可以看出,構造更優的二叉樹,原則就是權重越大的葉子,距離根應該越近,而我們的終級目標是生成「最優」的二叉樹,最優二叉樹必須符合下面兩個條件:

所有上層節點都大於等於下層節點。

某節點,設其較大的子節點為m,較小的子節點為n,m下的任一層的所有節點都應大於等於n下的該層的所有節點。

上面這個例子是比較簡單的,實際的檔案中,乙個位元組有256種可能的取值,所以二叉樹的葉子節點多達256個,最終的樹形可能非常複雜,但有一種非常精巧的演算法可以快速地建起一棵最優二叉樹,這種演算法由d.huffman(戴?哈夫曼)提出,下面我們先來介紹哈弗曼演算法的步驟,然後再來證明通過這麼簡單的步驟得出的樹形確實是一棵最優二叉樹。     哈夫曼演算法的步驟是這樣的:

比如上面的例子,哈弗曼樹建立的過程如下:

1) 列出原始的節點資料:

2) 將最小的兩個節點c和e結合起來:

3) 再將新的節點和a組合起來

4) 再將d節點加入

5) 如此迴圈,最終得到乙個最優二叉樹

生成的資料檔案長度為:     3*6 + 1*15 + 4*2 + 2*9 + 4*1 = 63

下面我們用逆推法來證明對於各種不同的節點序列,用哈弗曼演算法建立起來的樹總是一棵最優二叉樹:

按照哈弗曼樹的建立過程,新增的兩個節點是當前節點序列中最小的兩個,其他的任何兩個節點的父節點都大於(或等於)這兩個節點的父節點,只要前一步是最優二叉樹,其他的任何兩個節點的父節點就一定都處在它們的父節點的上層或同層,所以這兩個節點一定處在當前二叉樹的最低一層。

這兩個新增的節點是最小的,所以無法和其他上層節點對換。符合我們前面說的最優二叉樹的第乙個條件。

只要前一步是最優二叉樹,由於這兩個新增的節點是最小的,即使同層有其他節點,也無法和同層其他節點重新結合,產生比它們的父節點更小的上層節點來和同層的其他節點對換。它們的父節點小於其他節點的父節點,它們又小於其他所有節點,只要前一步符合最優二叉樹的第二個條件,到這一步仍將符合。

這樣一步步逆推下去,在這個過程中哈弗曼樹每一步都始終保持著是一棵最優二叉樹。

哈弗曼編碼 哈弗曼樹

哈弗曼編碼是依賴於字元使用頻率來建立的一種編碼,通過把使用頻率低的字元分配相對較多的01編碼,而使用頻率高的分配相對較低的01編碼,來建立最小的帶權路徑長度的樹,來最大化的獲得編碼儲存空間的一種編碼規則。這個樹稱為哈弗曼樹,也稱為最優二叉樹。這樣可以確定每乙個字元的編碼不可能成為其他字元編碼的坐子串...

哈弗曼編碼

include include include define my strmax 100 define infinity 1000000 typedef struct htnode,huffmantree 動態分配陣列儲存赫夫曼樹 typedef char huffmancode 動態分配陣列儲存赫...

哈弗曼編碼

include iostream include queue include vector include string using namespace std struct huffmantree bool operator const huffmantree t const vector h 相...