ZLIB算法學習

  我們的遊戲資源數據、例如圖片、聲音、腳本等,都是使用gzip壓縮的。之前做BREW的時候,大部分手機支持BREW的ZIP解壓接口,有的不支持,只好在網上找了一份解壓的代碼。找的代碼好像在解析壓縮數據頭部信息時,有點bug。另外在一些超低端機型上,解壓過程中會死機,懷疑是解壓需要的內存過大的原因。因爲不熟悉gzip壓縮的原理,當時胡亂改了改,有些問題也不了了之了。


  現在轉做智能平臺,看到很多引擎裏都使用了zlib模塊。上網查了查,發現zlib和gzip是使用的同樣的壓縮算法(deflate,另外png也是使用的這個噢)。但是我們在使用zlib解壓gzip壓縮的數據時也遇到了一些問題,後來發現是對zlib的接口不熟悉導致的誤用。經過這幾次挫折,以及見識了zlib應用的廣泛,我決定花些時間啃啃這塊硬骨頭,開始閱讀zlib的源代碼。


  這裏先說一下zlib接口的事情。zlib被設計成在內存有限的情況下,可以壓縮解壓遠遠超出內存大小的數據的能力,因此它提供的接口,也大多是對數據進行一段段的處理。我們使用時,圖省事,直接使用它提供的一個一次解壓的函數uncompress,但是這個函數實際上在zlib的默認條件下,無法識別gzip的頭部信息。查看這個函數的源代碼,發現它只不過是對zlib一些公共接口的封裝。參照它的寫法,只是修改一下deflateInit2函數的一個參數,就可以解壓gzip數據了。


   通過閱讀源碼直接理解zlib算法,對我還是一件比較困難的事情。建議先看看源代碼doc目錄下的幾個zlib標準文檔、以及zlib網站上的技術解釋文章。下面說下我對ZLIB算法的一些理解。


  ZLIB使用的defalte壓縮方法,簡單來說,就是先將數據中重複的字符串,替換成(距離,長度)對;再對替換後的數據,使用huffman編碼,將字符按出現頻率重新編碼。同時在替換過程中,保證不論數據有多大,算法所佔用的內存都是可控的。


  算法的思想很直觀,但具體到實現上,有一些難點。比如採用什麼方式查找一個字符串是否在前面出現過。直接的循環字符比較效率很低,我覺得zlib是參考了Rabin–Karp字符串查找算法,即使用hash方法來確定一個字符串是否在前面出現過。zlib壓縮過程中會維護一個比較大的hash值數組,這個數組存儲了數據流中每3個字符組成的字符串的hash值,例如4、5、6號字符計算一個hash值,5、6、7號字符也計算一個hash值。計算出的hash值作爲下標,用來在hash值數組裏存儲當前三字字符串的下標。當數據流中出現一個新字符時,和之前的兩個字符組成一個字符串,計算hash值,看在hash數組裏該值的位置是否已經有值,有的話就取出這個值(上一次得到這個hash值的三個字符的下標),檢查是否是有效匹配。可以將查找過程理解爲一個查字典的過程,只不過這個字典的條目也是處理過程中逐漸生成、逐漸拋棄的。

  

  zlib會將得到的純字符與(距離、長度)對中的距離統一編碼(0~285),長度單獨編碼(0~29)。當然這兩個範圍對於長度(3~258),距離(1~32768)來說都是不夠的,需要在編碼後緊跟額外bit來確定具體值。


  接下來的一步是對這兩個字符集使用huffman編碼。這時有兩種方式,靜態編碼和動態編碼。靜態編碼是指壓縮和解壓部分規定好一個靜態編碼方式,例如字符256~279編碼爲0000000~0010111,0~143編碼爲00110000~10111111。採用這種方式,壓縮數據中就不用包含每個字符對應的huffman編碼了。


  另外一種動態編碼,就是根據字符在數據中出現的頻率,動態構造huffman編碼。與教科書的算法相比,要加入一些限制。保證生成的huffman樹是唯一的。這樣的好處就是動態數據裏也不直接記錄編碼對應的huffman編碼,只要記錄huffman編碼的長度就好了。這個過程我是這樣理解的,生成的huffman樹的形狀,是左邊深度低、右邊深度高,葉子節點從左往右看,是先按頻率,再按字符在字典裏的順序排的序。這樣就比較好理解通過hunffman編碼長度,反推出字符-編碼對應關係的方法了。


  不過令我驚訝的是,動態編碼到這一步還沒有完,生成的huffman編碼長度序列,還要再經過一次RLE壓縮,即序列變成這樣:字符,字符,這個字符重複幾次...。RLE壓縮後的長度序列,單個元素的範圍是(0~18),其中0~15是huffman編碼長度,16~18是長度編碼重複次數(3~138,需要額外bit位確定)。然後,再把這個序列,來一次huffman編碼...


   明白了這些實現上的難點,源代碼還是很好理解的,只是對於爲什麼要這麼設計,我還有些漿糊。不過最近要學習的東西有點多,只能先理解到這種程度了。


參考資料:

zlib\doc下的各種文檔

zlib網站上的相關文章(zlib網站竟然被牆了,爲什麼)

一篇不錯的算法細節分析文章




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