目錄
前言
實例:
首頁 後端開發 Python教學 圖文詳解LZ77壓縮演算法編碼Python實作原理

圖文詳解LZ77壓縮演算法編碼Python實作原理

Mar 23, 2017 pm 04:05 PM

前言

LZ77演算法是無損壓縮演算法,由以色列人Abraham Lempel發表於1977年。 LZ77是典型的基於字典的壓縮演算法,現在很多壓縮技術都是基於LZ77。鑑於其在資料壓縮領域的地位,本文將結合圖片和原始碼詳細介紹其原理。

原理介紹

首先介紹幾個專業術語。

1.lookahead buffer(不知道怎麼用中文表述,暫時稱為待編碼區):

等待編碼的區域

2. search buffer:

已經編碼的區域,搜尋緩衝區

3.滑動視窗:

指定大小的窗,包含「搜尋緩衝區」(左) + 「待編碼區」(右)

接下來,介紹具體的編碼過程:

為了編碼待編碼區,編碼器在滑動視窗的搜尋緩衝區尋找直到找到符合的字串# 。匹配字串的開始字串與待編碼緩衝區的距離稱為“偏移值”,匹配字串的長度稱為“匹配長度”。編碼器在編碼時,會一直在搜尋區中搜索,直到找到最大匹配字串,並輸出(o, l ),其中o是偏移值, l是匹配長度。然後視窗滑動l,繼續開始編碼。如果沒有找到匹配字串,則輸出(0, 0, c),c為待編碼區下一個等待編碼的字符,視窗滑動「1」。演算法實作將類似下面的:

while( lookAheadBuffer not empty )
 {
 get a pointer (position, match) to the longest match
 in the window for the lookAheadBuffer;
output a (position, length, char());
 shift the window length+1 characters along;
 }
登入後複製

主要步驟為:

1.設定編碼位置為輸入流的開始

2.在滑窗的待編碼區查找搜尋區中的最大匹配字串

3.如果找到字串,輸出(偏移值, 匹配長度), 視窗向前滑動「匹配長度」

4. 如果沒有找到,輸出(0, 0, 待編碼區的第一個字元),視窗向前滑動一個單位

5.如果待編碼區不為空,回到步驟2

描述實在是太複雜,還是結合實例來講解吧

實例:

現在有字串“AABCBBABC”,現在對其進行編碼。

一開始,視窗滑入如圖位置

圖文詳解LZ77壓縮演算法編碼Python實作原理

由圖可見,待編碼緩衝區有「AAB」三個字符,此時搜尋緩衝區還是空的。所以編碼第一個字符,由於搜尋區為空,故找不到匹配串,輸出(0,0, A),視窗右移一個單位,如下圖

圖文詳解LZ77壓縮演算法編碼Python實作原理

此時待編碼區有「ABC」。開始編碼。最先編碼”A”,在搜尋區找到”A”。由於沒有超過待編碼區,故開始編碼”AB”,但在搜尋區沒有找到匹配字串,故無法編碼。因此只能編碼”A」。

輸出(1, 1)。即相對於待編碼區,偏移一個單位,匹配長度為1。視窗右滑動匹配長度,即移動1個單位。如下圖

圖文詳解LZ77壓縮演算法編碼Python實作原理

一樣,沒找到,輸出(0, 0, B),右移1個單號,如下圖

圖文詳解LZ77壓縮演算法編碼Python實作原理

輸出(0, 0, C),右移1個單位,如下圖

圖文詳解LZ77壓縮演算法編碼Python實作原理

#輸出(2, 1),右移1個單位,如下圖

圖文詳解LZ77壓縮演算法編碼Python實作原理

輸出(3, 1),右移1個單位,如下圖

圖文詳解LZ77壓縮演算法編碼Python實作原理

开始编码”A”,在搜索缓冲区查找到匹配字符串。由于待编码缓冲区没有超过,继续编码。开始编码”AB”,也搜索到。不要停止,继续编码“ABC”,找到匹配字符串。由于继续编码,则超过了窗口,故只编码“ABC”,输出(5, 3),偏移5,长度3。右移3个单位,如下图

圖文詳解LZ77壓縮演算法編碼Python實作原理

此时待编码缓冲区为空,停止编码。

最终输出结果如下

圖文詳解LZ77壓縮演算法編碼Python實作原理

python代码实现:

class Lz77:
    def init(self, inputStr):
        self.inputStr = inputStr #输入流
        self.searchSize = 5    #搜索缓冲区(已编码区)大小
        self.aheadSize = 3     #lookAhead缓冲区(待编码区)大小 
        self.windSpiltIndex = 0 #lookHead缓冲区开始的索引
        self.move = 0
        self.notFind = -1   #没有找到匹配字符串

    #得到滑动窗口的末端索引
    def getWinEndIndex(self):
        return self.windSpiltIndex + self.aheadSize

    #得到滑动窗口的始端索引
    def getWinStartIndex(self):
        return self.windSpiltIndex - self.searchSize

    #判断lookHead缓冲区是否为空
    def isLookHeadEmpty(self):
        return True if self.windSpiltIndex + self.move> len(self.inputStr) - 1   else False

    def encoding(self):
        step = 0
        print("Step   Position   Match   Output")
        while not self.isLookHeadEmpty():
            #1.滑动窗口
            self.winMove()
            #2. 得到最大匹配串的偏移值和长度
            (offset, matchLen) = self.findMaxMatch()
            #3.设置窗口下一步需要滑动的距离
            self.setMoveSteps(matchLen) 
            if matchLen == 0:
                #匹配为0,说明无字符串匹配,输出下一个需要编码的字母
                nextChar = self.inputStr[self.windSpiltIndex]
                result = (step, self.windSpiltIndex, '-',  '(0,0)' + nextChar)
            else:
                result = (step, self.windSpiltIndex, self.inputStr[self.windSpiltIndex - offset: self.windSpiltIndex - offset + matchLen], '(' + str(offset) + ',' + str(matchLen) + ')')
            #4.输出结果
            self.output(result)    
            step = step + 1        #仅用来设置第几步

    #滑动窗口(移动分界点)
    def winMove(self):
        self.windSpiltIndex = self.windSpiltIndex + self.move

    #寻找最大匹配字符并返回相对于窗口分界点的偏移值和匹配长度
    def findMaxMatch(self):
        matchLen = 0
        offset = 0
        minEdge = self.minEdge() + 1  #得到编码区域的右边界
        #遍历待编码区,寻找最大匹配串
        for i in range(self.windSpiltIndex + 1, minEdge):
            #print("i: %d" %i)
            offsetTemp = self.searchBufferOffest(i)
            if offsetTemp == self.notFind: 
                return (offset, matchLen)
            offset = offsetTemp #偏移值

            matchLen = matchLen + 1  #每找到一个匹配串,加1

        return (offset, matchLen)

    #入参字符串是否存在于搜索缓冲区,如果存在,返回匹配字符串的起始索引
    def searchBufferOffest(self, i):
        searchStart = self.getWinStartIndex()
        searchEnd = self.windSpiltIndex 
        #下面几个if是处理开始时的特殊情况
        if searchEnd < 1:
            return self.notFind
        if searchStart < 0:
            searchStart = 0
            if searchEnd == 0:
                searchEnd = 1
        searchStr = self.inputStr[searchStart : searchEnd]  #搜索区字符串
        findIndex = searchStr.find(self.inputStr[self.windSpiltIndex : i])
        if findIndex == -1:
            return -1
        return len(searchStr) - findIndex

    #设置下一次窗口需要滑动的步数
    def setMoveSteps(self, matchLen):
        if matchLen == 0:
            self.move = 1
        else:
            self.move = matchLen

    def minEdge(self):
        return len(self.inputStr)  if len(self.inputStr) - 1 < self.getWinEndIndex() else self.getWinEndIndex() + 1

    def output(self, touple):
        print("%d      %d           %s     %s" % touple)

if name == "main":
    lz77 = Lz77("AABCBBABC")
    lz77.encoding()
登入後複製

只是简单的写了下,没有过多考虑细节,请注意,这不是最终的代码,只是用来阐述原理,仅供参考。输出结果就是上面的输出(格式由于坑爹的博客园固定样式,代码位置有偏移,请注意




以上是圖文詳解LZ77壓縮演算法編碼Python實作原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何解決Linux終端中查看Python版本時遇到的權限問題? 如何解決Linux終端中查看Python版本時遇到的權限問題? Apr 01, 2025 pm 05:09 PM

Linux終端中查看Python版本時遇到權限問題的解決方法當你在Linux終端中嘗試查看Python的版本時,輸入python...

如何在使用 Fiddler Everywhere 進行中間人讀取時避免被瀏覽器檢測到? 如何在使用 Fiddler Everywhere 進行中間人讀取時避免被瀏覽器檢測到? Apr 02, 2025 am 07:15 AM

使用FiddlerEverywhere進行中間人讀取時如何避免被檢測到當你使用FiddlerEverywhere...

在Python中如何高效地將一個DataFrame的整列複製到另一個結構不同的DataFrame中? 在Python中如何高效地將一個DataFrame的整列複製到另一個結構不同的DataFrame中? Apr 01, 2025 pm 11:15 PM

在使用Python的pandas庫時,如何在兩個結構不同的DataFrame之間進行整列複製是一個常見的問題。假設我們有兩個Dat...

Uvicorn是如何在沒有serve_forever()的情況下持續監聽HTTP請求的? Uvicorn是如何在沒有serve_forever()的情況下持續監聽HTTP請求的? Apr 01, 2025 pm 10:51 PM

Uvicorn是如何持續監聽HTTP請求的? Uvicorn是一個基於ASGI的輕量級Web服務器,其核心功能之一便是監聽HTTP請求並進�...

在Linux終端中使用python --version命令時如何解決權限問題? 在Linux終端中使用python --version命令時如何解決權限問題? Apr 02, 2025 am 06:36 AM

Linux終端中使用python...

如何在10小時內通過項目和問題驅動的方式教計算機小白編程基礎? 如何在10小時內通過項目和問題驅動的方式教計算機小白編程基礎? Apr 02, 2025 am 07:18 AM

如何在10小時內教計算機小白編程基礎?如果你只有10個小時來教計算機小白一些編程知識,你會選擇教些什麼�...

如何繞過Investing.com的反爬蟲機制獲取新聞數據? 如何繞過Investing.com的反爬蟲機制獲取新聞數據? Apr 02, 2025 am 07:03 AM

攻克Investing.com的反爬蟲策略許多人嘗試爬取Investing.com(https://cn.investing.com/news/latest-news)的新聞數據時,常常�...

See all articles