C++實現的Huffman轉碼器及相應程式架構的設計

來源:互聯網
上載者:User

前面用python實現了基於256個字元huffman及範式huffman轉碼器。Python確實適合快速實現演算法,包括程式的架構設計的實現。

但是無奈雖然嘗試最佳化但是速度仍然不盡如意,包括無法實現inline,以及動態語言的特性決定這種強調速度,處理大資料量的應用程式顯然不適合用python實現。

正好看了關於基於模版的演算法庫設計的一些皮毛,以及以前看CGAL庫的學到一些方法。這裡嘗試用C++寫一個壓縮解壓縮的架構程式,當前實現的架構還很幼稚,

是考慮到能夠實現Huffman,範式huffman的基於256個字元,以及基於word單詞的壓縮與解壓縮。也就是能夠實現

1. 基於字元編碼的huffman壓縮,解壓縮

2.基於字元編碼的範式huffman壓縮,解壓縮

3.基於單詞編碼的huffman壓縮,解壓縮

4.基於單詞編碼的範式hufman壓縮,解壓縮

這些都是基於頻率的(字元頻率,單詞頻率)的壓縮演算法。

TODO

考慮系統能方便的加入其它演算法

如LZ77(不是基於頻率的壓縮)等。。。。

OK,目前僅僅初步搭起了架構,實現了上面提到的1,基於字元編碼的huffman壓縮,解壓縮。

當前程式在http://golden-huffman.googlecode.com/svn/trunk/glzip_c++/

同時架構儘可能考慮到後序加入不同演算法的方便性,不同演算法的共同與不同之處,層次關係,相同部分的複用,避免重複代碼。程式裡面寫了一個Buffer類,用於提供基於緩衝的的讀寫

byte操作,以減少fread,fwrite的調用次數。實踐證明能夠提高效率,相比每次fread,fwrite 1個byte不帶緩衝,同時使得代碼清晰。

 

還沒有嘗試演算法的最佳化,比如當前解碼的時候一個unsigend int 轉換成相應的bit,採用最笨的動態計算。

可以考慮查表法最佳化。

不過當前的速度可python實現的比已經快多了。

在我的1G記憶體虛擬機器上跑,

壓縮,然後解壓縮一個24M的文本,總共用時大概7-8秒。用GCC編譯器最佳化選項-O2能夠達到3-4秒完成。

 

程式的架構上,首先考慮定義兩個類

Compressor,Decompressor

 

提供壓縮,解壓縮的流程架構。對於使用者而言

Compressor<> compressor(infile_name, outfile_name);

compressor.compress();

即完成壓縮工作。解壓縮類似。

template<template<typename> class _Encoder = HuffEncoder,typename _KeyType = unsigned char>class Compressor {public:Compressor(const std::string& infile_name, std::string& outfile_name): encoder_(infile_name, outfile_name) {}/**The overall process of compressing,compressing framework*/void compress() {encoder_.caculate_frequency();encoder_.gen_encode();//-------------------------------write the compressed fileencoder_.write_encode_info();encoder_.encode_file();  }private:_Encoder<_KeyType> encoder_;  //using enocder_ right now can be HuffEncoder or CanonicalEncoder };template<template<typename> class _Decoder = HuffDecoder,typename _KeyType = unsigned char>class Decompressor {public:Decompressor(const std::string& infile_name, std::string& outfile_name): decoder_(infile_name, outfile_name) {}/**The overall process of decompressing, decompressing framework*/void decompress() {//-----------------------------read header--------decoder_.get_encode_info();//-----------------------------read file content---decoder_.decode_file();}private:_Decoder<_KeyType> decoder_;};

採用複合的設計方法,Compressor類使用encoder_完成壓縮工作。Decompressor類使用decoder_完成解壓縮的工作。

模版參數上,template<typename> class _Encoder = HuffEncoder, 標明可以採用HuffEncoder完成基於傳統huffman的壓縮,

同時我們可以定義CanonicalEncoder類,令template<typename> class _Encoder = CanonicalEncoder就可以方便的使得

Compressor類使用基於範式huffman的encoder_完成壓縮工作。

而 typename _KeyType = unsigned char標明預設Compressor是採用基於字元(256個字元)作為key的,進行編碼解碼。

那麼後面我們加入基於單詞的編碼方法,就可以採用使得typename _KeyType = std::string即可,或者也可以用char*這裡暫時都按照單詞用string儲存考慮。

 

壓縮的過程就是

計算字元(或單詞)頻率

進行編碼,利用構造的huffman tree

寫編碼資訊到輸出檔案

編碼輸入檔案輸出到輸出檔案

 

在這個過程中我們需要儲存

1.得到頻率hash表          字元(或單詞) –> 頻率   

2.得到的編碼hash表      字元(或單詞) –>  編碼

另外我們需要處理輸入輸出,需要FILE* infile_,FILE* outfile_所有這些我們作為encoder所擁有的變數。

     HuffEncoder is a Encoder,繼承Encoder,同樣的以後加入的CanonicalEnocder is also a Encoder也會繼承Encoder.

     Encoder所提供的非虛函數介面,caculate_frequency()和encode_file()等,標明這些由Encoder類提供實現,也即對於

傳統Huffman還是範式Huffman來說,這些操作的實現是相同的,複用基類的實現。

但是其它的虛函數則要他們提供各自不同的實現。

另外當前的處理,對於基於字元編碼的情況,_KeyType = unsigned char,

使用的所謂雜湊表並不是STL裡面的雜湊表,而就是一個數組,例如 frequency_map_對於基於字元編碼的情況,它就是 long long (&)[256]類型的數組。

這樣利用了unsigned char 不超過256個byte,並且轉int值之後正好當成一個hash函數,用STL的hash就小題大作了,速度也慢多了。

但是考慮相容以後的string,基於單詞編碼的情況就得用STL hash了,或者你自己寫hash。

所以這裡採用了traits手法,根據_KeyType的不同,選擇不同類型的 Hash容器類型,並且在函數中也會根據不同的情況,指派到不同的執行函數char –> char_tag

string –> string_tag。(當然以後也可以考慮給long long (&)[256]類型的數組這種簡單的hash,加上與STL hash相同的介面,從而是代碼更加同一,避免分配函數,不過目前感覺那樣太費時間了。

下面是根據不同的_KeyType,給出不同的類型設定。

//基於字元情況的encoder<unsigned char>.caculate_frequencey(),以後實現的基於單詞情況的則會調用encoder<std::string>.do_caculate_frequencey(string_tag)

00034   typedef typename TypeTraits<_KeyType>::FrequencyHashMap        FrequencyHashMap;00035   typedef typename TypeTraits<_KeyType>::EncodeHashMap           EncodeHashMap;00036   typedef typename TypeTraits<_KeyType>::type_catergory type_catergory;00037 public:00047   void caculate_frequency() {00048     do_caculate_frequency(type_catergory());00049   }00050   
00080   void do_caculate_frequency(char_tag) {00081     Buffer reader(infile_);00082     unsigned char key;00083     while(reader.read_byte(key))00084       frequency_map_[key] += 1;00085     //std::cout << "Finished caculating frequency\n"; 00086   }
//---------------------------------------------------------------------------00021 struct normal_tag {};00022 struct char_tag: public normal_tag {};00023 struct string_tag: public normal_tag {};0002400025 struct encode_hufftree {};00026 struct decode_hufftree {};00027 //----------------------------------------------------------------------------0002800029 //---TypeTraits,from here we can find the HashMap type 00030 template <typename _KeyType>00031 class TypeTraits {00032 public:00033   typedef normal_tag  type_catergory;00034   typedef std::tr1::unordered_map<_KeyType, size_t> HashMap;00035 };00036 //---special TypeTraits for unsigned char00037 template<>00038 class TypeTraits<unsigned char> {00039 public:00040   typedef char_tag type_catergory;00041   typedef long long count[256];00042   typedef count     FrequencyHashMap;00043   typedef std::vector<std::string>    EncodeHashMap;00044 };00045 //---special TypeTraits for std::string00046 template<>00047 class TypeTraits<std::string> {00048 public:00049   typedef string_tag type_catergory;00050   typedef std::tr1::unordered_map<std::string, size_t>        FrequencyHashMap;00051   typedef std::tr1::unordered_map<std::string, std::string>   EncodeHashMap;
 
 
 
HuffEncoder,利用複合設計模式,採用HuffTree來協助實現編碼。
 
 
為了Huffman壓縮過程和解壓縮過程,我利用模版類的特化設計了兩個不同的HuffTree分別用於壓縮過程,而解壓縮過程。它們繼承一個HuffTreeBase,提供共有的資料root_和操作如delete_tree().
這裡感覺最不爽的還是GCC採用的不認模版父類的名稱必須顯示指明或者用this->,據說VC8就不需要顯示指明或者加this,那多好啊,感覺真是沒必要,麻煩的要命。尤其是剛開始你覺得只要一個
類,後來你要寫一個類似但是不同的類,覺得可以提出一個基類的時候,你發現你把共同的代碼提出去了,剩下的代碼原來可以用的現在卻要加很多this,麻煩死了啊還不如不複用,直接複製快呢。
 
 
 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.