English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

guest
1 / ?
back to lessons

Huffman 如何構建最優編碼

Hamming 將 Huffman 編碼呈現為一種貪心演算法,該演算法構建最小平均長度的無前綴編碼。關鍵想法:自下而上構建樹,始終合併兩個機率最低的符號。

前向傳遞(構建)

1. 將所有符號按機率從高到低排序。

2. 取兩個機率最低的符號。將它們合併為一個新的元符號,其機率 = 兩者之和。

3. 將元符號插入其排序位置。

4. 重複直到只剩兩個符號。

5. 為剩餘的兩個符號分配 0 和 1。

後向傳遞(分配編碼)

逆向撤銷合併:在每次分割處,被合併的兩個符號接收與其組合父符號相同的前綴位,加上額外的 0(一個子符號)或 1(另一個子符號)。0/1 分配是任意的——兩者都有效。

Huffman 構建:合併與解碼樹

為什麼這是最優的:如果任何其他編碼的平均長度 L' 更小,應用相同的前向化簡最終會產生兩個符號,其平均長度小於 1 比特——對於 2 符號編碼來說是不可能的。矛盾。

追蹤演算法

Hamming 的示例:四個符號 A、B、C、D,機率分別為 p(A)=0.5、p(B)=0.25、p(C)=0.125、p(D)=0.125。

前向傳遞:

步驟 1:排序:A(0.5)、B(0.25)、C(0.125)、D(0.125)。最低的兩個:C、D。

步驟 2:合併 CD,機率=0.25。新列表:A(0.5)、B(0.25)、CD(0.25)。

步驟 3:最低的兩個:B(0.25)、CD(0.25)。合併 BCD,機率=0.5。

步驟 4:剩餘兩個符號:A(0.5)、BCD(0.5)。分配 A=0、BCD=1。

後向傳遞:

BCD → B 得到 10、CD 得到 11。CD → C 得到 110、D 得到 111。

最終編碼:A=0 (l=1)、B=10 (l=2)、C=110 (l=3)、D=111 (l=3)。

L = 0.5·1 + 0.25·2 + 0.125·3 + 0.125·3 = 1.75 比特。

將 Huffman 演算法應用於:p(X1)=0.4、p(X2)=0.3、p(X3)=0.2、p(X4)=0.1。顯示所有合併步驟、每個符號的最終編碼,並計算 L。

多個有效的 Huffman 編碼

Hamming 注意到非唯一性的兩個來源:

1. 任意的 0/1 分配。在每次分割處,您可以給任一子節點分配 0。交換整個編碼中的 0 和 1 會產生不同的編碼,其平均長度 L 相同。

2. 平手打破。當兩個節點機率相等時,任一個都可以被放置在更高的位置(先合併)。不同的平手打破選擇可以產生結構不同的樹——'長'與'茂密'——具有相同的 L 但不同的編碼長度分佈。

長樹與茂密樹

長樹(偏斜):每個深度級別一個符號(Fibonacci 類的結構)。編碼長度差異很大:一個符號獲得短編碼,其他符號級聯為更長的編碼。

茂密樹(平衡):符號均勻分佈在深度級別。編碼長度聚集在平均值附近。較低的方差。

長樹與茂密 Huffman 樹

Hamming 的建議:在有選擇的情況下,更喜歡茂密樹。相同的 L,但編碼長度的方差更小 → 更統一的解碼時間 → 實時應用中所需的緩衝區更小。

計算編碼長度方差

編碼長度方差:Var = E[l²] − (E[l])²

對於編碼 {A=0 l=1、B=10 l=2、C=110 l=3、D=111 l=3},機率為 p=[0.5, 0.25, 0.125, 0.125]:

E[l] = L = 1.75

E[l²] = 0.5·1² + 0.25·2² + 0.125·3² + 0.125·3² = 0.5 + 1.0 + 1.125 + 1.125 = 3.75

Var = 3.75 − 1.75² = 3.75 − 3.0625 = 0.6875

等機率符號的替代茂密編碼使用所有 2 長度編碼:L=2、Var=0。

考慮 4 個等機率符號 (p=0.25 each)。計算 H。然後比較:(a) 茂密編碼 {00、01、10、11},所有長度 = 2,和 (b) 長度為 {1、2、3、3} 的長編碼。計算各自的 L 和 Var。您應該選擇哪一個,為什麼?

壓縮收益 vs 符號分佈

Hamming 的規則:Huffman 編碼只有在符號機率差異很大時才值得。

等機率。如果所有 2^k 個符號機率相等,均為 1/2^k,Huffman 產生分塊編碼:每個符號獲得長度 k。L = H = k。與簡單分塊編碼相比沒有收益。

偏斜的機率。如果一個符號佔主導(p >> 1/2^k 對其他人),Huffman 為其分配一個非常短的編碼(長度 1 或 2),大幅降低 L。

逗號編碼(Hamming 的術語)。當每個機率超過剩餘總數的 2/3 時,Huffman 自然產生:p(s1)→0、p(s2)→10、p(s3)→110、...,直到末尾的兩個等長編碼。這是一個'逗號編碼':1 後面的尾隨 0 充當逗號。

Hamming 指出:現實世界的數據壓縮(備份、文件歸檔)當源具有偏斜機率時可以減少超過一半的存儲——英文文本是主要例子。

Huffman 與分塊編碼:數值比較

Hamming 的第二個例子:p(s1)=1/3、p(s2)=1/5、p(s3)=1/6、p(s4)=1/10、p(s5)=1/12、p(s6)=1/20、p(s7)=1/30、p(s8)=1/30。

分塊編碼:8 個符號 → 各 3 位 → L_block = 3。

Hamming 計算 Huffman 編碼並報告 L_Huffman ≈ 2.58 比特。

節省:(3 − 2.58)/3 ≈ 14% 相對分塊編碼的壓縮。

當符號機率差異很大時(此處 1/3 vs 1/30,比例 10:1),變長編碼大幅節省。

上述 8 符號源有 H ≈ 2.55 比特(您無需驗證)。Hamming 的 Huffman 編碼達到 L ≈ 2.58 比特。分塊編碼使用 L = 3 比特。計算:(a) Huffman 編碼的 L/H,(b) 分塊編碼的 L/H,以及 (c) 這些比率告訴您相對於理論最小值的每個編碼的效率如何。

自編譯程序

Hamming 在第 11 章結束時提出了一個引人注目的想法:Huffman 編碼器可以對自己進行編碼。解碼樹(告訴解碼器如何讀取壓縮信息)與壓縮數據一起傳輸。接收器不需要先驗知道編碼。

編碼器:對數據進行採樣、估計機率、構建 Huffman 編碼、將解碼樹編碼為頭部、然後編碼數據。

解碼器:讀取頭部以重建樹,然後使用它解碼數據。

Hamming 的觀點:整個管道可以作為庫函數運行,無需人工參與。您調用它,它自動壓縮和解壓縮。現代歸檔格式(ZIP、gzip、bzip2)實施完全相同的模式。

更深層的原則:智能在演算法中,而不在固定的編碼表中。該演算法適應它接收的任何數據。這是 Hamming 在所有偉大工程系統中看到的模式:適應性內置其中,而不是後來添加。

Hamming 說自編譯 Huffman 編碼器'不需要人工干預或思考。'這個性質的工程美德是什麼,它對演算法的設計要求什麼?舉一個體現同一原則的現代系統的具體例子。