關於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 的時間內找到最值。任何乙個葉子結點的值改變...