第五節 詞典編碼
有許多場合,開始時不知道要編碼數據的統計特性,也不一定允許我們事先知道它們的統計特性。因此,人們提出了許許多多的數據壓縮方法,企圖用來對這些數據進行壓縮編碼,在實際編碼過程中以儘可能獲得最大的壓縮比。這些技術統稱爲通用編碼技術。詞典編碼(Dictionary Encoding)技術就是屬於這一類,這種技術屬於無損壓縮技術。
一.詞典編碼分類
詞典編碼的根據是數據本身包含有重複代碼序列這個特性。例如文本文件(碼詞表示字符)和光柵圖像(碼詞表示像素)就具有這種特性。
詞典編碼法的種類很多,歸納起來分爲兩類。
第一類詞典法的想法是企圖查找正在壓縮的字符序列是否在前面的輸入數據中出現過,如果是,則用指向早期出現過的字符串的“指針”替代重複的字符串。這種編碼思想如圖03-05-1所示。
圖03-05-1 第一類詞典法編碼概念
這裏的“詞典”是隱含的,指用以前處理過的數據。這類編碼中的所有算法都是以Abraham Lempel和Jakob Ziv在1977年開發和發表的算法(稱爲LZ77算法)爲基礎。此算法的一個改進算法是由Storer和Szymanski在1982年開發的,稱爲LZSS算法。
第二類算法的想法是企圖從輸入的數據中創建一個“短語詞典(dictionary of the phrases)”。編碼數據過程中當遇到已經在詞典中出現的“短語”時,編碼器就輸出這個詞典中的短語的“索引號”,而不是短語本身。這個概念如圖03-05-2所示。
圖03-05-2 第二類詞典法編碼概念
A.Lempel和J.Ziv在1978年首次發表了介紹這種編碼方法的文章,稱爲LZ78。在他們的研究基礎上,Terry A.Welch在1984年發表對這種編碼算法進行了改進的文章,並首先在高速硬盤控制器上應用了這種算法。因此後來把這種編碼方法稱爲LZW(Lempel-Ziv Walch)壓縮編碼。
二.LZ77算法 1977年,Jacob Ziv和Abraham Lempel描述了一種基於滑動窗口緩存的技術,該緩存用於保存最近剛剛處理的文本(J. Ziv and A. Lempel, “A Universal Algorithm for Sequential Data Compression”, IEEE Transaction on Information Theory, May 1977)。這個算法一般稱爲IZ77。 LZ77和它的變體發現,在正文流中詞彙和短語(GIF中的圖像模式)很可能會出現重複。當出現一個重複時,重複的序列可以用一個短的編碼來代替。壓縮程序掃描這樣的重複,同時生成編碼來代替重複序列。隨着時間的過去,編碼可以重用來捕獲新的序列。算法必須設計成解壓程序能夠在編碼和原始數據序列推導出當前的映射。 在研究LZ77的細節之前,先看一個簡單的例子(J. Weiss and D. Schremp, “Putting Data on a Diet”, IEEE Spectrum, August 1993)。考慮這樣一句話: the brown fox jumped over the brown foxy jumping frog 這個短語的長度總共是53個八位組 = 424 bit。算法從左向右處理這個文本。初始時,每個字符被映射成9 bit的編碼,二進制的1跟着該字符的8 bit ASCII碼。在處理進行時,算法查找重複的序列。當碰到一個重複時,算法繼續掃描直到該重複序列終止。換句話說,每次出現一個重複時,算法包括儘可能多的字符。碰到的第一個這樣的序列是the brown fox。這個序列被替換成指向前一個序列的指針和序列的長度。在這種情況下,前一個序列的the brown fox出現在26個字符之前,序列的長度是13個字符。對於這個例子,假定存在兩種編碼選項:8 bit的指針和4 bit的長度,或者12 bit的指針和6 bit的長度。使用2 bit的首部來指示選擇了哪種選項,00表示第一種選項,01表示第二種選項。因此,the brown fox的第二次出現被編碼爲 <00b><26d><13 d >,或者00 00011010 1101。 壓縮報文的剩餘部分是字母y;序列<00b><27d><5 d >替換了由一個空格跟着jump組成的序列,以及字符序列ing frog。 圖03-05-3演示了壓縮映射的過程。壓縮過的報文由35個9 bit字符和兩個編碼組成,總長度爲35 x 9 + 2 x 14 = 343比特。和原來未壓縮的長度爲424比特的報文相比,壓縮比爲1.24。
圖03-05-3 LZ77模式例 (一)壓縮算法說明 LZ77(及其變體)的壓縮算法使用了兩個緩存。滑動歷史緩存包含了前面處理過的N個源字符,前向緩存包含了將要處理的下面L個字符(圖03-05-4(a))。算法嘗試將前向緩存開始的兩個或多個字符與滑動歷史緩存中的字符串相匹配。如果沒有發現匹配,前向緩存的第一個字符作爲9 bit的字符輸出並且移入滑動窗口,滑動窗口中最久的字符被移出。如果找到匹配,算法繼續掃描以找出最長的匹配。然後匹配字符串作爲三元組輸出(指示標記、指針和長度)。對於K個字符的字符串,滑動窗口中最久的K個字符被移出,並且被編碼的K個字符被移入窗口。 圖03-05-4(b)顯示了這種模式對於我們的例子的運行情況。這裏假定了39個字符的滑動窗口和13個字符的前向緩存。在這個例子的上半部分,已經處理了前面的40個字符,滑動窗口中是未壓縮的最近的39個字符。剩下的源字符串在前向窗口中。壓縮算法確定了下一個匹配,從前向窗口將5個字符移入到滑動窗口中,並且輸出了這個匹配字符串的編碼。經過這些操作的緩存的狀態顯示在這個例子的下半部分。
(a)通用結構
(b)例子 圖03-05-4 LZ77模式 儘管LZ77是有效的,對於當前的輸入情況也是合適的,但是存在一些不足。算法使用了有限的窗口在以前的文本中查找匹配,對於相對於窗口大小來說非常長的文本塊,很多可能的匹配就會被丟掉。窗口大小可以增加,但這會帶來兩個損失:(1)算法的處理時間會增加,因爲它必須爲滑動窗口的每個位置進行一次與前向緩存的字符串匹配的工作;(2)<指針>字段必須更長,以允許更長的跳轉。 (二)壓縮算法描述 爲了更好地說明LZ77算法的原理,首先介紹算法中用到的幾個術語:
LZ77編碼算法的核心是查找從前向緩衝器開始的最長的匹配串。算法的具體執行步驟如下:
例:待編碼的數據流如表03-05-1所示,編碼過程如表03-05-2所示。現作如下說明:
表03-05-1 待編碼的數據流
表03-05-2 編碼過程
(三)解壓算法 對於LZ77壓縮文本的解壓很簡單。解壓算法必須保存解壓輸出的最後N個字符。當碰到編碼字符串時,解壓算法使用<指針>,和<長度>,字段將編碼替換成實際的正文字符串。
|