python 實現的範式huffman壓縮,解壓縮

來源:互聯網
上載者:User
程式僅為自己學習之用。關於範式huffman的介紹http://blog.pfan.cn/lingdlz/36436.html前面寫了huffman壓縮,解壓縮的程式

http://www.cnblogs.com/rocketfan/archive/2009/09/12/1565610.html

程式改寫了一下,加入了範式huffman壓縮,解壓縮。 實現在設計上利用compressor.py,decompressor.py定義兩個架構類給出壓縮,解壓縮的架構流程,huffman和範式huffman繼承這兩個架構,並給出不同的實現,同時範式huffman的壓縮會複用一部分huffman壓縮的函數實現。利用list,和索引,實現合并分組,來類比二叉樹的建立,並未實際建立二叉樹,來計算每個字元對應的encoding應該有的長度,也即葉子深度(等同與huffman編碼的長度)。具體就是每次在優先對列中選擇兩個權重最小的節點,然後將兩個節點所對應的葉子組裡面的所有葉子(字元)的深度加1,再將合并後的節點放入隊列(權重相加,同時合并兩個葉子分組為一組)。注意由於建立二叉樹的時候選擇最小的兩個節點時可能會有多個相同的最小節點供選擇,所以huffman編碼並不唯一。得到每個字元的encoding的長度後,具體encode的時候從encoding length從小到大排序,進行編碼。也即頻率大的字元先編碼,加入最小的encoding length為3則第一個編碼為000,和http://blog.pfan.cn/lingdlz/36436.html中介紹的實現唯一的不同是沒有記錄所有encoding length,對應的第一個encoding而是記錄最後一個,這樣實現更方便些。如length   3, 3 , 5 , 5 , 6 ,6 ,6 ,6 分別記錄紅色位置對應的encoding。3   0003   0015   010005   010016   0101006   0101016   0101106   010111這樣編碼的好處是,從000到010111按照字典序,字串比較是從小到大的。同時考慮 000 = 0      001 = 1      01000 =  8       01001 = 9        010100 = 20....  010111 = 23 即編碼對應的int值也是從小到大的。這裡一個方案是記錄編碼資訊A(3,1),(5,9),(6,23),注意由於編碼可能有比較長的如19位,則不能一個byte儲存數值,具體實現的時候還是儲存成B (3, 001), (5, 01001),(6, 010111),解碼的時候在恢複出A的形式。下面是最基本的一個範式huffman解碼方法,每次讀1byte判斷解碼 1         num = 0
 2         length = -1 #the actual encoding length - 1
 3         while 1:
 4             c = self.infile.read(1) 
 5             if c == '':
 6                break
 7             li = huffman.convert(c)    #'a',asc 97,返回 一個list 內容是97對應的各個位元字
 8             for x in li:
 9                 num = (num << 1) + int(x)    #TODO num = (num << 1) & int(x) quick??
10                 length += 1
11                 if(num <= self.decoder.last_list[length]):
12                     index = self.decoder.index_list[length] - (self.decoder.last_list[length] - num)
13                     self.outfile.write(self.decoder.key_list[index])  #OK we decode one character
14                     num = 0
15                     length = -1 正確性壓縮率和huffman壓縮一樣(顯然的:)),無論採用那種壓縮,最後解壓縮後得到的文本和原文本如有不同,是因為原文本最後有多餘的分行符號,python讀檔案的時候會忽略最後多餘的分行符號號。 速度速度上,當前的實現兩種壓縮差不多。不過都慢的很,呵呵,壓縮一個24M的文本,得到13M的文本用時1分多,解壓縮要4分多。 TODO1.  對於範式huffman解壓縮來說,可以考慮在演算法層次上的,解壓縮最佳化,包括 查表等方法,可參考http://blog.csdn.net/Goncely/archive/2006/03/09/619725.aspx TODO2.  具體剖析器速度瓶頸,那些地方影響了速度,是讀寫檔案慢還是其它的地方包括讀寫後的轉換。能否利用將核心地方C預言書實現或者參                                    考http://syue.com/Programming/Procedures/Python/73952.html提高程式速度。 TODO3.  有無現成的python轉碼器參考,總覺得輸入,輸出的處理有些繁瑣可能影響速度。 TODO4.  參考學習gzip的實現, LZ..演算法的實現。 TODO5.   改用c++實現,看速度差異。 TODO6.   考慮分詞, 用詞w ord 作為編碼解碼的單元,而不是現在的 字元character(byte),對比速度和壓縮率。用詞做編碼單元會使得要編碼的符號數目更多,更能體現               範式huffman的優點。 當前程式 /Files/rocketfan/glzip.rar

def usage():    """glzip 1.txt                      #will compress 1.txt to 1.txt.crs using huffman method        glzip -d 1.txt.crs             #will decompress 1.txt.crs to 1.txt.crs.de         glzip -c 1.txt                   #will cocompress 1.txt to 1.txt.crs2  using canonical huffman method        glzip -d -c  1.txt.crs2      #will decompress 1.txt.crs2 to 1.txt.crs2.de  using canonical huffman method    """程式的效能分析:首先分析採用普通的huffman方法壓縮檔,初步判斷,IO是程式瓶頸,按照一次讀檔案一個byte,一次寫檔案寫一個byte的方法,讀寫大檔案極其耗時。考慮下面的代碼,一次讀一個byte,讀完整個檔案,對於一個24M的檔案,利用cProfile在我的vmware,ubutu系統運行: time python -m cProfile ../glzip.py caesar-polo-esau.txt > 2.log

1 def readFile(self):
2     self.infile.seek(0)
3     while 1:
4         c = self.infile.read(1) 
5         if c == '':
6             break     ompressing,huffman,encode character(byte)Compressing caesar-polo-esau.txt result is caesar-polo-esau.txt.crs         24292439 function calls in 59.029 CPU seconds   Ordered by: standard name   ncalls  tottime  percall  cumtime  percall filename:lineno(function)  1   31.151   31.151   59.018   59.018 compressor.py:16(readFile)耗時1分鐘。對於完整的huffman壓縮程式的其流程如下,調用huffman.Compressor.compress()1   def compress(self):
2         self.caculateFrequence()
3         self.genEncode()
4         self.__writeCompressedFile()        

6  def __writeCompressedFile(self):
7         self.outfile.seek(0)
8         self.writeEncodeInfo()
9         self.encodeFile()可以看出,程式的時間幾乎全部花費在caculateFrequence()和encodeFile()上,分別對應讀檔案計算字元使用頻率,和編碼寫檔案。caculateFrequence() 會讀一遍輸入檔案,encodeFile()會再讀一遍輸入檔案,並編碼寫入輸出檔案。$./time python -m cProfile -s time ../glzip.py caesar-polo-esau.txt > 1.logcompressing,huffman,encode character(byte)Compressing caesar-polo-esau.txt result is caesar-polo-esau.txt.crs         74845611 function calls (74845219 primitive calls) in 263.437 CPU seconds   Ordered by: internal time   ncalls  tottime  percall  cumtime  percall filename:lineno(function)        1  117.427  117.427  192.423  192.423 huffman.py:124(encodeFile) 48584258   59.195    0.000   59.195    0.000 {method 'read' of 'file' objects}        1   43.486   43.486   70.979   70.979 huffman.py:77(caculateFrequence) 13127563   28.971    0.000   28.971    0.000 {method 'write' of 'file' objects}對比下僅僅執行讀寫相同檔案的函數的已耗用時間,僅僅執行下面的readFile和writeFile,顯然99%的時間花在了IO代價上。 1     def readFile(self):
 2         self.infile.seek(0)
 3         self.byteSum = 0
 4         while 1:
 5             c = self.infile.read(1) 
 6             self.byteSum += 1
 7             if c == '':
 8                 break    
 9     def writeFile(self):
10         self.outfile.seek(0)
11         c = 'a'
12         for i in range(self.byteSum):
13             self.outfile.write(c)compressing,huffman,encode character(byte)Compressing caesar-polo-esau.txt result is caesar-polo-esau.txt.crs         48584571 function calls in 150.294 CPU seconds   Ordered by: internal time   ncalls  tottime  percall  cumtime  percall filename:lineno(function) 24292129   50.546    0.000   50.546    0.000 {method 'write' of 'file' objects}        1   37.005   37.005   65.026   65.026 compressor.py:16(readFile)        1   33.557   33.557   85.248   85.248 compressor.py:24(writeFile) 24292129   28.022    0.000   28.022    0.000 {method 'read' of 'file' objects}顯然第一個需要最佳化的地方是檔案的讀寫,一次讀寫1byte會帶來大量的read,write,影響效率。需要加入緩衝機制,先讀入緩衝區在處理,在http://blog.csdn.net/dwbclz/archive/2006/04/06/653294.aspx提到1.使用小塊的讀寫緩衝,經測試,緩衝大小在32K~64K之間效果比較好。我測試了一下對於讀,一次read(100)和一次read(1000)對於同樣的24M的檔案,耗時分別變為0.326,0.031,顯然是線性。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.