Huffman編碼的8種實現方式

簡介

這裏給出的源代碼huffman.zip用8種不同的方式實現了Huffman編碼算法。這些代碼意在演示不同Huffman算法的實現原理,比較算法執行效率的差別,但並沒有針對實際應用環境的需求,做更多的空間或效率優化。所有代碼以C++語言編寫,爲了更容易地實現各種數據結構,代碼中大量應用了標準C++庫和模板技術。——總之,這些代碼的作用在於示例和演示;如果大家想把這些代碼應用在實際應用中,可能還需要做進一步的調整和優化。

我在2003年9月的《程序員》雜誌上發表了“奇妙的二叉樹”一文,對這8種算法進行了詳細的講解。這裏,我只給出8種算法的概要描述。

這8種實現方式分別是:

  • huffman_a:使用鏈表結構生成Huffman樹的算法,這是最基本的實現方法,效率最低。
  • huffman_b:使用《數據結構》(嚴蔚敏,吳偉民,1997,C語言版)中給出的算法,將二叉樹存放在連續空間裏(靜態鏈表),空間的每個結點內仍有左子樹、右子樹、雙親等指針。
  • huffman_c:使用Canonical Huffman編碼,同時對huffman_b的存儲結構進行改造,將二叉樹存放在連續空間tree裏,空間的每個結點類型都和結點權值的數據類型相同,空間大小爲2*num,tree[0]未用,tree[1..num]是每個元素的權值,生成Huffman後,tree[1..2*num-1]中是雙親結點索引。
  • huffman_d:在huffman_c的基礎上,增加預先排序的功能先用QuickSort算法對所有元素的權值從小到大排序,這樣,排序後最前面的兩個元素就是最小的一對元素了。我們可以直接將它們挑出來,組合成一個子樹。然後再子樹的權值用折半插入法插到已排序的元素表中, 保證所有結點有序。爲了保證初始元素的順序不變,我們另外使用了一個索引數組,所有排序中的交換操作都是在索引數組中進行的。
  • huffman_e:在huffman_d的基礎上,將索引數組放在tree的內部。爲編碼方便,將元素權值放在tree[num..2*num-1]處。將tree[0..num-1]作爲索引數組。排序改爲從大到小。對索引數組排序後,每次從最後選出2個最小值,相加後的結點權值放在索引數組最後,結點索引放在索引數組中倒數第2個位置,然後索引數組大小減1,並將最後一個索引值插入到前面的有序表中,保證索引數組仍然有序。
  • huffman_f:在huffman_e的基礎上,將排序改爲利用堆排序原理選擇最小的兩個權值。也即,將所有元素的權值組織成堆後,每次堆內的根結點就是最小值了。每取出一個根結點後,就把堆尾元素調到根結點重建堆。取出兩個最小值合併成一個子樹後,再把子樹作爲葉子結點放到堆中,並讓其上升到合適的位置,保持堆性質不變。因爲每次不必完成整個排序過程,而只是組織成堆,因此,這種方法要比使用快速排序更快。上述算法參考了mg-1.2.1中Huffman編碼的實現,見http://www.cs.mu.oz.au/mg/
  • huffman_g:當元素權值已經有序時,可以使用A. Moffat和J. Katajainen設計的在權值數組內部構建Huffman的方法。A. Moffat和J. Katajainen對該算法的描述見http://www.cs.mu.oz.au/~alistair/abstracts/inplace.html
  • huffman_h:在huffman_f的基礎上,增加限制碼長的功能。限制碼長的算法參考了zlib-1.1.4中構造限制碼長的Huffman編碼的源代碼。zlib的源代碼見http://www.gzip.org/zlib/,其中限制長度的算法在tree.c的gen_bitlen()函數中。

上述8種算法分別對應於8個同名C++類,這些類都是由huffman_base類派生的。huffman_base類提供了與Huffman算法相關的大多數通用功能,如編碼轉換、Canonical Huffman編碼生成、Huffman編碼驗證等等。

main.cpp中的tester類提供了用隨機數據測試上述8種算法,並顯示算法的運行時間及運行結果的功能。

下載

下載Huffman編碼的8種實現方式(ZIP格式,39KB)

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