基於Huffman和LZ77壓縮(三)LZ77思路分析

Huffman壓縮詳細分析

LZ77: 基於重複語句的壓縮

1 什麼是LZ77

1977年兩個以色列人提出的基於重複語句上的通用的壓縮算法--------將重複語句替換成更短的<長度, 距離, 下個字符串首字母>對的方式。 真正的LZ77用的是一個三元組(長度距離對 + 下一個語句的首字母 )

在這裏插入圖片描述

爲什麼叫基LZ77算法的壓縮?

上邊介紹了 原LZ77 的處理方式:
<長度, 距離, 下個字符串首字母> 三字節

我們發現:下個字符串的首字母對壓縮目的來說沒什麼幫助,放大看卻佔了很多空間,因此 我們採用<長度, 距離>的方式

長度距離對 我們仍採用三個字節
長度 :1字節表示
距離 :2字節表示

實現思想:

要壓縮文件,必然需要將待壓縮文件讀到程序的緩衝區中,因此我們需要在程序中維護一段緩衝區

LZ77 :緩衝區的大小 :64K
那麼我們也用64K

我們將緩衝區等分爲兩部分:

查找緩衝區32K:

       1  存放已經壓縮完成的數據,
   
       2  待壓縮的數據中的每個字符串(語句)需要在該區域中找是否重複
    
       3  隨着壓縮的不斷進行,查找緩衝區不斷增大 

先行緩衝區32K:

	  1 存放待壓縮的數據   
	  
      2 每次取出一個字符串(語句)去查找緩衝區中匹配
      
      3 隨着壓縮的不斷進行,先行緩衝區的大小不斷變小

壓縮核心是將重複語句替換爲長度距離對:

那麼重複字符串的長度爲幾的時候進行長度距離對的替換?

1 確定長度:

用1字節表示
首先 :匹配字符串的長度我們用一個字節存儲:範圍【0,255】

爲什麼用一個字節存儲:
1: 一個字節能表示的最大長度已經比較大了,
2: 用更長的長度來存儲時對壓縮率有一定影響,因爲匹配串的距離大部分小於255。

2 確定距離

怎麼確定距離:
距離是先行緩衝區離查找緩衝區的最遠距離

線性緩衝區:32K 查找緩衝區:32K
那麼極端距離爲64K —> 2^16
所以2字節就能表示

1 確定距離受緩衝區的影響:

查找緩衝區越大,能查找到匹配的概率越大,但匹配查找的時間代價也增大了真正查找長度不會超過32K

2。距離再過遠 ,存儲長度就得用更多的字節,又浪費了壓縮空間。

所以真正查找匹配的範圍不會超過32K(一半長度)==>2^3 * K —>2^15 那麼我們用兩個字節來進行保存長度(2^16)

確定壓縮條件

長度爲1個字節的語句 : 不壓縮
長度爲2個字節的語句 : 沒必要(長度距離對是3個字節,那麼肯定不划算)

所以 :
長度 >=3 時開始匹配替換:
Min_Match_Len =3;
Max_Match_Len =258 (利用了0 ,1,2 用不到的空間)

技術纔是硬道理

問題1:如何快速查找匹配?

(查找匹配的時間嚴重影響壓縮時間)
暴力匹配太慢
我們用哈希的思想

哈希 :
首先需要一個哈希表,每次是3個字符進行存儲,哈希表中將來保存的是從查找緩衝區中取到的三個字符中首字符 在查找緩衝區中的下標
在這裏插入圖片描述

問題2 :你可能會想,想要匹配必須先構建哈希彪表 , 構建哈希表肯定得需要遍歷一趟來存儲哈希表中,這不是又影響了時間嗎?

遇到凡事------不要慌~~~

 我們讓在哈希表中匹配位置和哈希表的構造進行同步進行就可以了。
 
 什麼意思呢?
 邊走邊構造:哈希表中存0那就是該位置沒保存,那麼保存在該位置就行了,哈希表中存1的位置就是存在衝突了,衝突那我們一會再來解決衝突。
需要確定哈希函數

字符串哈希函數我們可以網上查一下

 哈希表中匹配位置則需要確定哈希函數,該字符串哈希函數只起將字符串轉爲唯一整形數字的作用,我們可以網上查這個哈希函數

LZ77 哈希函數:
A(4,5) +b(6,7,8)^B(1,2,3) + B(4,5) + B(6,7,8)^C(1,2,3)+ C(4,5,6,7,8)
A B C 代表第一、二、三個位置
12345678 代表字符的比特位
+是連接起來的意思
^優先於+

由哈希函數可以確定 哈希地址最大有15個比特位。

舉個栗子🌰理思路:

🌰:
1 從先行緩衝區中拿到一個字符串abc,
2 通過哈希函數計算在哈希表中的位置
3 到哈希表中取匹配字符串在查找緩衝區的位置

只要三個字符(字符串)相同,那麼計算出的哈希地址一定相同,然後就相當於知道了查找緩衝區的位置,於是就可以確定一個長度距離對了

三個字符的組合數量256* 256* 256 ;
哈希表的大小,因爲組合方式不一樣,哈希函數計算結果必須一一映射

那這樣的話?
哈希表必須有2^24個位置,
每個位置存儲的是在64K窗口中的下標
64K窗口的下標範圍 :【0,2^16】;
每個下標2個字節存儲
那麼就需要兩個字節表示距離.2^24 * 2 ==>32M

**其實查了下資料,還真不是這樣搞的。。。**

因爲32M的哈希表太大,隨着壓縮的進行,哈希表中的內容要不斷更新,更不好維護。

因此 實際LZ77算法哈希表中的位置個數給2^15 —>32K(其實之前的哈希函數可以推出來哈希地址的範圍)

乾貨來了~

32K的哈希表表必然會存在哈希衝突,那麼怎麼解決衝突的?

實際緩衝區:64K=32K + 32K

開闢一個同樣大的Prev作爲處理哈希衝突的空間(32K)

1 爲什麼Prev和Head一樣大?

	因爲當匹配暫停時,需要將右窗WSIZE數據導入到左窗中

2 什麼時候匹配會暫停?
在這裏插入圖片描述

匹配暫停發生在線性緩衝區的末尾,當先行緩衝區中剩餘的字符數量不足最大匹配長度時,我們認爲這次匹配不夠完全,因此暫不進行。

怎麼做?

1 將先行緩衝區中的32K數據全部導入到查找緩衝區,相當於更新了查找緩衝區

2 從文件中接着讀取32K(Wsize )的文件
那麼繼續從start位置(上次匹配串進行的位置)開始匹配查找

這樣存在一個小誤區 :你可能會認爲這樣查找緩衝區不足32K了,會不會出錯?

答案是不會的!!

此時查找緩衝區的確是變小了,但倘若在此小區間找不到,那麼久默認此串不存在重複,那麼就把這個新字符串加入到哈希表中就行了,不用向更遠的地方找,損失但性能也是微乎其微的,甚至是有益的!

爲什麼損失性能微乎其微甚至有益?

首先 查找緩衝區變小,那麼查找的更快。
倘若向前接着找的話,也不一定能找到匹配串,這下你明白了嗎?

暫時小結一下:

當前存在問題1: 32K的哈希表必然存在哈希衝突
**當前存在問題2:**對於長度大於64K的文件仍無法進行壓縮

下一篇:我們來展開探究這兩個問題,歡迎持續關注。

點我跳轉下一篇

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