給定乙個文字中出現的一組字元c,每個字元有其出現頻率freq,想構造字元的最優二進位制表示,即用來編碼整個文字的二進位制位最少
定長編碼:每個字元用相同長度的二進位制位數進行編碼,則每個字元的長度n必須滿足,2^n = |c|
變長編碼:思想是賦予高頻字元短碼字,賦予低頻字元長碼字
編碼過程相對簡單,將表示每個字元的碼字連線起來即可完成檔案壓縮
解碼過程,如果採用的定長編碼則直接解碼,變長編碼可能產生歧義比較麻煩;但又一種變長編碼是無歧義的——字首嗎
字首碼,即沒有任何碼字是其他碼字的字首;所以編碼檔案的開始碼字是無歧義的
檔案的最優編碼方案總是對應一棵滿(full)二叉樹,即每個非葉節點都有兩個孩子節點【證明很簡單,反正即可,假設一棵非滿二叉樹是最優編碼方案,取其不擁有兩個孩子節點的非葉節點,分情況,如果它沒有孩子節點,則取以其兄弟節點為根的的樹的葉子節點為其孩子節點,這種編碼方案更優,因此矛盾;如果它有左孩子節點或者右孩子節點,則取其存在的孩子節點上的葉子節點作為另外乙個孩子節點,這種編碼方案更有,也矛盾,因此得證】
構造霍夫曼編碼
c是字元集合,有n個字元,出現頻率分別為c.freq;演算法自底向上的構造出對應最優編碼的二叉樹。
從|c|個葉節點開始,執行|c|-1個「合併」操作建立出最終的二叉樹
使用乙個以屬性freq為關鍵字最小的最優優先佇列q,從而識別最低頻率的兩個字元將其合併;當合併兩個字元時,得到的新節點的頻率設定兩者頻率之和
huffman(c)
n = |c|
q = c
//q是最小優先佇列,假定使用最小二叉堆實現,則時間複雜度為o(n)
for i = 1 to n-1
//自底向上提取頻率最小的兩個節點組成新的節點
allocate a new node z
z.left = x = extract-min(q)
z.right = y =
extract-min(q)
z.freq = x.freq + y.freq
insert(q, z)
return extract-min(q) //最後只剩下根節點
霍夫曼編碼的思想並不難,也容易理解;較難的地方在於證明其正確性【滿足貪心選擇性質和最優子結構性質】和程式設計實現
貪心選擇性質:
x和y是c中頻率最低的兩個字元,則存在c的乙個最優字首編碼,x和y的碼字長度相同,且只有最後乙個二進位制位不同
最優子結構性質:
x和y是c中頻率最低的兩個字元,c去掉字元x和y,加入乙個新字元z
得到c',z.freq = x.freq + y.freq;t'是c'的乙個最優字首碼對應的編碼樹,則將t'中葉節點z替換為乙個以x和y為孩子的內部結點,得到樹t,t表示字母表c的乙個最優字首碼
在這裡證明第二個性質,基於第乙個
b(t)表示按t進行編碼需要多少二進位制位
首先b(t) = b(t') + x.freq + y.freq(因為x和y的深度都比z多1)
反證法:假設t對應的字首碼不是最優字首碼,t''才是,則b(t'') < b(t)
由性質一,t''包含兄弟節點x和y,
令t'''為t''中將x/y及他們的父結點替換為葉節點z得到的樹,則
b(t''') = b(t'') - x.freq - y.freq < b(t) - x.freq - y.freq = b(t')
與t'是最優字首碼矛盾,因此得證。
霍夫曼編碼
一 八卦 在 演算法為什麼這麼難?這篇部落格裡,劉未鵬講了乙個八卦 根據wikipedia的介紹,霍夫曼同學 當年還在讀ph.d,所以的確是 同學 而這個問題是坑爹的導師robert m.fano 給他們作為大作業的 fano自己和shannon合作給出了乙個suboptimal的編碼方案,為得不到...
霍夫曼編碼
霍夫曼編碼,或者也可以說哈夫曼編碼。它是一種編碼方式,是可變長編碼 vlc 的一種。準確來說,它是一種方法,什麼方法呢?這種方法,它完全依據字元出現的概率來構造異字頭的平均長度最短的碼字。哈夫曼編碼使用變成編碼表對源字元進行編碼,而這個變長編碼表是通過估算源字元出現的概率得到的。它有個特點,就是出現...
霍夫曼編碼
霍夫曼編碼是可變字長編碼 vlc 的一種。huffman於1952年提出一種編碼方法,該方法完全依據字元出現概率來構造異字頭的平均長度最短的碼字,有時稱之為最佳編碼,一般就稱huffman編碼。霍夫曼編碼的具體方法 先按出現的概率大小排隊,把兩個最小的概率相加,作為新的概率 和剩餘的概率重新排隊,再...