範式哈夫曼編碼(Canonical Huffman Code)

本文來自:http://blog.csdn.net/lpt19832003/article/details/1713718  感謝大神無私奉獻!

1 概念介紹

哈夫曼編碼是一種最優的前綴編碼技術,然而其存在的不足卻制約了它的直接應用。首先,其解碼時間爲O(lavg), 其中lavg爲碼字的平均長度;其次,更爲最重要的是,解碼器需要知道哈夫曼編碼樹的結構,因而編碼器必須爲解碼器保存或傳輸哈夫曼編碼樹。對於小量數據的壓縮而言,這是很大的開銷。因而,應用哈夫曼編碼的關鍵是如何降低哈夫曼編碼樹的存儲空間。Faller[1973]提出的自適應哈夫曼編碼技術使哈夫曼編碼樹的存儲空間降爲零,即在使用某種約定的情況下,解碼器能動態地重構出和編碼器同步的哈夫曼編碼樹,而不需要任何附加數據。這樣做的代價便是時間開銷的增大。另一種技術是編碼器和解碼器使用事先約定的編碼樹,這種方法只能針對特定數據使用,不具備通用性。另外一種,也是最爲常用的方法,便是範式哈夫曼編碼。現在流行的很多壓縮方法都使用了範式哈夫曼編碼技術,如GZIB、ZLIB、PNG、JPEG、MPEG等。
範式哈夫曼編碼最早由Schwartz[1964]提出,它是哈夫曼編碼的一個子集。其中心思想是:使用某些強制的約定,僅通過很少的數據便能重構出哈夫曼編碼樹的結構。其中一種很重要的約定是數字序列屬性(numerical sequence property),它要求相同長度的碼字是連續整數的二進制描述。例如,假設碼字長度爲4的最小值爲0010,那麼其它長度爲4的碼字必爲0011, 0100, 0101, ...;另一個約定:爲了儘可能的利用編碼空間,長度爲i第一個碼字f(i)能從長度爲i-1的最後一個碼字得出, 即: f(i) = 2(f(i-1)+1)。假定長度爲4的最後一個碼字爲1001,那麼長度爲5的第一個碼字便爲10100。最後一個約定:碼字長度最小的第一個編碼從0開始。通過上述約定,解碼器能根據每個碼字的長度恢復出整棵哈夫曼編碼樹的結構。

2 碼字構造

假設有如下的碼長序列:
 符號:a b c d e  f  g h  i  j  k ... u 
 碼長:3 4 4 4 4 4 4 4 4 5 5 ... 5
使用count[i]表示長度爲i的碼字的數目,first[i]表示長度爲i的第一個碼字的整數值。根據約定3,即first[3] = 0可得到符號a的範式哈夫曼編碼爲000。再根據約定2,可得到first[4] = 2*(first[3]+1) = 2,進一步可知b的編碼爲0010。由約定1可構造出符號c的編碼爲0011,由此類推可構造出整個碼字空間如下:
a=000(0);  f=0110(6);  k=10101(21);
b=0010(2);  g=0111(7);  ...
c=0011(3);  h=1000(8);  u=11111(31);
d=0100(4);  i=1001(9);
e=0101(5);  j=10100(20);

其中first[3] = 0, first[4] = 0010b = 2, first[5] = 10100b = 20

3 解碼算法

範式哈夫曼編碼有一個很重要的特性:長度爲i的碼字的前j位的數值大於長度爲j的碼字的數值,其中i > j。如上例中的最小五位碼10100,它的前四位1010大於任何的四位碼。由這個特性,很容易構造出範式哈夫曼編碼的解碼算法
extern KBitInputStream bs;
int len = 1;
int code = bs.ReadBit();
while(code >= first[len])
{
 code <<= 1;
 code |= (bs.ReadBit()); // append next input bit to code
 len++;
}
len--;

// 至此,識別出了一個前綴碼,下面將code解碼爲其對應的符號sym
int index = index[len]+(code-first[len]);
int sym = table[index];

其中while循環用於確定碼長,這也是解碼算法中至關重要的一步,確定碼長的算法效率影響着整個解碼算法的效率。比如說我們要解碼100110100序列,當循環至len=4的時候,code等於1001,大於len[4],因而循環繼續,繼續讀取下一位,code=10011, len=5,小於len[5]=10100,所以循環結束,執行下面的len--代碼,得到了正確的碼字長度4。算法實現需要注意幾點:一定要使用code >= first[len],而不是code > first[len];另外,len--不能少。

代碼中index[len]表示長度爲len的第一個碼字的索引,index[3] = 0, index[4] = 1, index[5] = 9。不難發現,index[i] = count[i-1]+count[i-2]+...+count[1]+count[0],其中count[0] = 0。

4 其他特性

對於長度爲i的碼字而言,count[i] <= (2^i)-first[i]。其中等號僅對最大長度的碼字成立。
如果對於碼字的最大長度imax,count[imax] < (2^imax)-first[imax],那麼稱輸入的碼字長度序列爲不完全集。

參考文獻

[1] Faller, N. 1973. An Adaptive System for Data Compression. Record of the 7th Asilomar Conf. on Circuits, Systems and Computers (Pacific Grove, Ca., Nov.), 593-597. 
[2] Schwartz E.S. Kallick B,. Generating a cannonical prefix encoding, Communications of the ACM 7(1964), 166-169.



發佈了23 篇原創文章 · 獲贊 15 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章