哈弗曼編碼幾乎是所有壓縮演算法的基礎,其實這個演算法並不複雜,簡單的理解就是,如何用更短的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.定義 哈夫曼編碼主要用於資料壓縮。哈夫曼編碼是一種可變長編碼。該編碼將出現頻率高的字元,使用短編碼 將出現頻率低的字元,使用長編碼。變長編碼的主要問題是,必須實現非字首編碼,即在乙個字符集中,任何乙個字元的編碼都不是另乙個字元編碼的字首。如 0 10就是非字首編碼,而0 01不是非字首編碼。2....
哈夫曼樹 哈夫曼編碼
定義從a結點到b結點所經過的分支序列為從a結點到b結點的路徑 定義從a結點到b結點所進過的分支個數為從a結點到b結點的路徑長度 從二叉樹的根結點到二叉樹中所有結點的路徑長度紙盒為該二叉樹的路徑長度 huffman樹 帶權值路徑長度最小的擴充二叉樹應是權值大的外界點舉例根結點最近的擴充二叉樹,該樹即為...
哈夫曼編碼 哈夫曼樹
哈夫曼樹是乙個利用權值進行優化編碼的乙個比較奇怪的樹,他的實現比較簡單,用途也比較單一。哈夫曼樹的實現,實現要求 通過哈夫曼樹可以保證在編碼過程中不會出現例如 1000和100這樣的編碼規則,否則就會編碼失敗,因為1000和100在某些情況下的編碼會一模一樣。通過哈夫曼樹可以保證權值大的值進行編碼時...