deflate樹與deflate編碼

2022-04-07 16:09:44 字數 3880 閱讀 5089

關於deflate樹,能搜到的資料非常少,這個概念來自gzip的壓縮演算法,是

由huffman樹轉變過來的。這裡簡單記錄下deflate樹的生成過程以及deflate編碼。

假設以5 8 9 10 14 15,建立一顆huffman樹,可以是這個樣子的:

61

/\2734

/ \ /\

1413

1519

/ \ /\

58910

也可以交換任意結點的兩棵子樹

61

/\34

27/ \ /\

1519

1413

/ \ /\

91058

交換的過程雖然會改變葉子結點的huffman編碼,但是,不會改變huffman樹的帶權路徑和,也不會改變每個葉子結點的編碼長度。基於這一點,我們可以做個更特殊的變換,每一層,讓非葉子結點排在右邊,葉子結點排在非葉子結點的左邊。上面這棵樹的變換之後如下:

61

/\3427

/ \ /\

1514

1913

/ \ /\

91058

經過變換後,上面這顆樹就稱為deflate樹。同樣,deflate樹雖然改變了結點的huffman編碼,但是沒有改變每個元素的編碼長度。在gzip壓縮中的語義就是沒有改變壓縮率。

上面的變化用語言表達起來不好理解,再用乙個例子說明:

假設下面是乙個huffman樹:

a

/\b c

/ \ /\

d e f g

/ \ /\

g h i j

/\

k l

/\m n

轉化為deflate之後,如下:

a

/\b c

/ \ /\

d g f e

/ \ /\

i j h g

/\

k l

/\m n

那麼,轉換為deflate樹有什麼好處呢?

這涉及到碼表的記錄。所謂的碼表就是元素及其對應的編碼。

先看下正常huffman編碼下碼表的記錄

還是以5 8 9 10 14 15為集合,以下面這顆huffman樹為例:

61

/\3427

/ \ /\

1519

1413

/ \ /\

91058

假設走左為0,走右為1,那麼碼表就是:

15          14              9             10            5            8

00          10             010         011           110        111

為了能夠解碼,我們必須把這個碼表記錄下來。

再看下轉換為deflate樹後,如何記錄

上面這顆樹轉換後如下:

61

/\3427

/ \ /\

1514

1913

/ \ /\

91058

假設還是走左為0,走右為1。轉換後元素的編碼改變了,碼表應該如下:

15          14              9             10            5            8

00          10             100         101           110        111

雖然元素的編碼變化了,但不要緊,只要我們記錄如上這個碼表,還是能把資料還原的。

前邊說過,deflate雖然改變了編碼,但是每個元素的編碼長度是不變的,這個時候,可以只記錄每個元素的編碼長度,就可以在解碼的時候把資料還原。現在,碼表這麼記錄,每一層,從左往右記錄葉子結點的編碼長度,層次按從上到下。先記錄第2層(根節點為第0層)的兩個葉子,再記錄第三次的4個葉子,碼表如下:

15          14                 9         10            5            8

2            2                 3           3             3            3

先別管如何根據這個碼表解碼,先對比下這兩種記錄法,會發現,下面這種碼表記錄要比上面的碼表記錄節省位元,2的二進位制位10   ,  3的二進位制位11   ,總的位元位6*2=12。

而上邊的編碼總長度為2+2+3+3+3+3=16(15、14的編碼長度2,9、10、5、8的編碼長度為3)。這並不是偶然,因為乙個元素的編碼的長度(10的編碼長度為3)所佔的二進位制位元位(10的編碼長度3,佔二進位制2位)肯定小於等於編碼所佔的長度(10的編碼長度3)。

這就是記錄碼長的好處,為什麼要這麼計較這一丁點的位元呢,要知道,deflate樹是用於壓縮演算法的,而且這樣做並不複雜,何樂而不為?

現在再來說一下,有了這個碼表如何解碼,解碼是編碼的逆過程,所以,先看deflate樹的編碼

deflate樹,編碼方式為:

第n層的最左邊的葉子結點的編碼=((第n-1層的最左邊的葉子結點的編碼 )+  (第n-1層的葉子結點數))<< 1 。

第n層,後乙個葉子結點的編碼 = 前乙個葉子結點的編碼+1

還以下面這顆樹為例:

61

/\3427

/ \ /\

1514

1913

/ \ /\

91058

15的編碼為00

那麼9的編碼 = (上一層最左邊的葉子結點15的編碼+上一層的葉子結點數2)<<1

=   (00 + 10)<<1

=    100

10的編碼 = 9的編碼+1 = 101

5的編碼  = 10的編碼+1 = 110

8的編碼  = 5的編碼+1 = 111

現在可以說解碼過程了,碼表先搬下來:

15          14                 9         10            5            8

2            2                 3           3             3            3

由於這個碼表的記錄方法是每層葉子結點從左到右,並且層次從上到下的方式,而且,會發現,編碼長度就是葉子所在的層次(假設根節點為第0層)。所以,第二層開始出現了第乙個葉子結點,第乙個葉子結點一定是一直往左的。那麼根據編碼規則15的編碼就是00,14的編碼是01,9的編碼是(00+2)<<1 = 100...

樹與樹演算法

樹 英語 tree 是一種抽象資料型別 adt 或是實作這種抽象資料型別的資料結構,用來模擬具有樹狀結構性質的資料集合。它是由n n 1 個有限節點組成乙個具有層次關係的集合。把它叫做 樹 是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點 每個節點有零個或多個子節點 沒...

樹與樹演算法

樹 英語 tree 是一種抽象資料型別 adt 或是實作這種抽象資料型別的資料結構,用來模擬具有樹狀結構性質的資料集合。它是由n n 1 個有限節點組成乙個具有層次關係的集合。把它叫做 樹 是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點 比如說 霍夫曼樹 用於資訊編碼...

勝者樹與敗者樹

概念介紹 勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個葉子結點相當於乙個選手,每個中間結點相當於一場比賽,每一層相當於一輪比賽。不同的是,勝者樹的中間結點記錄的是勝者的標號 而敗者樹的中間結點記錄的敗者的標號。勝者樹與敗者樹可以在log n 的時間內找到最值。任何乙個葉子結點的值改變...