基於Huffman和LZ77的壓縮(四)LZ77壓縮原理分析

點我查看上一篇

上一篇分析中,我們遇到了兩個問題:
問題1: 64K的哈希表必然存在哈希衝突
問題2: 大於64K的文件仍無法進行壓縮

下面我們來接着探索分析:

爲什麼給32K的查找緩衝區Head?

爲什麼給32K個位置,理論計算爲 2^24個才能計算完這些組合呀,那這樣必然存在哈希衝突,那麼LZ77怎麼解決衝突?

我們先不考慮大於64K的文件

將哈希表分爲2部分 Prev和Head

Prev空間專門解決哈希衝突,第一個地址的下標先存在prev【addr】

Head存放當前待匹配鏈的頭的下標,出現過即存在 衝突
在這裏插入圖片描述

哈希衝突具體怎麼解決

在這裏插入圖片描述
下面這張圖詮釋了發生哈希衝突的做法
:1 將當前位置保存在哈希函數計算出來的Head下標位置
2 該位置若爲0 ,則直接放入
3 該位置若非0 ,則存在衝突,接着向前找最遠的距離,並將地址的指向依次更改。
在這裏插入圖片描述

那麼大於64K的文件,必然會破壞原有的鏈的指向

64K以上的文件下標大於2個字節的存儲範圍了

取出的字符串的首字母的下標大於prev的最大空間,豈不是越界了,那怎麼辦?

處理方式將 pos & (pos-1)
pos & (pos-1)
pos-1 稱爲掩碼Vmask

引入新問題:
Pos & Vmask雖然能解決越界問題,但卻引入了新問題。當文件大於64K時可能破壞原有環鏈而形成死循環。

注意:此處的鏈指的是下標關係形成的指向。我們稱爲鏈。

1形成環狀鏈
在這裏插入圖片描述
環狀鏈肯定會在查找時形成死循環。
怎麼解決死循環?

設置最大匹配次數爲255,再多默認找不到了,放棄本次匹配,爲什麼設置255,再長就說明距離太遠了

問題2 :搭到別的鏈上

這種情況發生後, 下一次相同串到時候也找不到,那麼到時候會將該字符串計算出來地址 ,直接插入到哈希表中就可。

假設 待壓縮文件大小超過64K,則不能一次將其加載到程序緩衝區中:
因爲每次可以匹配的最大字符串的長度爲255, 當當前剩餘的帶匹配的字符串不足255時,另一部分文件還未加載到緩衝區中,則本次匹配暫時不進行,即 :線性緩衝區中剩餘數據到一定數量時暫不進行匹配 :

MIN_LOOKAHEAD >= MAX_MATCH + 1
即先行緩衝區中剩餘字符大於258

MAX_MATCH 是爲了能夠保證本次匹配能夠達到最大258

爲什麼 + 1:+1 是爲了保證完本詞匹配後,還能保證下次匹配

在這裏插入圖片描述
當匹配暫停時(先行緩衝區中剩餘的數據不能給保證本次匹配到最大長度+和下次匹配開始)

1 將WSIZE2 中的數據 導入(memcpy)到WSIZE1中
2 再從文件向WSIZE2(先行緩衝區)中接着加載數據
3 更新哈希表(之前的匹配數據實效),此時真正的匹配距離不是WSIZE,而是 WSIZE - LOOKAHEAD。

開始壓縮

從文件中每次讀取然後一句哈希函數計算哈希地址,插入即可,遇到衝突則進行衝突處理。

直到壓縮進行結束。

存在問題:壓縮的時候能進行,那麼如何解壓縮?

換句話說:解壓縮時,怎麼知道是原字符串還是壓縮後的長度距離對呢?

遇到凡事不要慌~
我們在壓縮文件的時候製作一份標記文件即可。

什麼是標記文件?

將原有的字符每次寫入標記爲0,而替換成的長度距離對我們將其標記爲1

那麼就是說標記文件到時候就是一串0101010的數字。
我們又想到了位圖,節省空間還很巧妙。

位圖的思想:將原文件與壓縮後的長度距離對標記爲 每個比特位存1個字符串

在解壓縮時:
遇到0,便直接獲取
遇到1,則知道是長度距離對了,則向前查找,第一字節是長度,接下來2-3字節是距離,
獲取距離後
獲取長度
就可以找到原串的樣子,便可以解壓縮了。

兩個文件的合併:
交給用戶時我們應該給一份壓縮文件就行了,所以應該將標記文件和壓縮文件進行合併:

所以我們還應該應該將標記文件寫入到壓縮文件中去。

寫入時在文件默認加上原文件的大小,可以防止解壓縮出現細小的差異。

小結:

當前雖然解決了哈希衝突的問題 ,
但是對於大於64K的文件,還是不能進行壓縮,下一篇我們再來解決

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章