壓縮入門
簡單的壓縮法 - Run-length Encoding
直接跑過字串,把重複的資料單元以一個該資料單元以及代表次數的數字做表示。 對於具有許多重複性的資料較有用,例如:簡單的圖像、簡單的影像, 對於分佈較複雜的資料比較沒有效,甚至會讓檔案變大。
範例:
輸入
WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
輸出
12W1B12W3B24W1B14W
或是
W12B1W12B3W24B1W14
Run-length encoding 還可以用很多不同的方法表示, 例如對於重複資料較少的資料, 可以改採「重複兩個字元加數字時代表該字元的次數, 而只出現一個字元時就直接代表該字元」, 藉此省去只有一個字元時的多餘表示。
範例:
輸入
WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
輸出
WW12BWW12BB3WW24BWW14
如果做完 Run-length encoding 後還要套用其他的壓縮演算法時, 為了要更好壓縮, 可以把出現次數跟原本的資料分離, 藉此可以分開處理。
範例:
輸入
WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
輸出
WWBWWBBWWBWW
12,12,3,24,14
此作法特別適用於 icons, 也是早期圖像壓縮的常用手法(例如線上服務 CompuServe), 直到後來更複雜的格式出現(例如 GIF)。 雖然 JPEG 有效地把這作法用於前處理過後(轉換、quantizing image blocks)所剩下的係數, 但此作法在照片類的圖片比較不適用。 另外 Run-length encoding 早期也有用於電視訊號(1967 年)。
一些 Run-length encoding 常見的地方:
- Truevision TGA
由 Truevision 於 1984 年釋出的圖片格式
- PackBits
Apple 早期所使用的格式
- PCX
由 ZSoft Corporation 於 1985 年釋出的圖片格式
- ILBM
由 Electronic Arts 於 1985 年釋出的圖片格式,用於早期的遊戲
- T.45
國際電信聯盟(ITU,International Telecommunication Union)訂定的傳真標準
結合 Modified Huffman coding 一起使用
因為傳真常常是一堆空白,偶爾有些資料,所以壓縮成果蠻有效的
簡單的壓縮法(改進) - BWT
BWT 是 Burrows–Wheeler transform 的縮寫, 該演算法會將字串重新排列, 產生的結果會有較多的連續重複字元。 這對於壓縮演算法很有利(例如 move-to-front transform 或 run-length encoding)。 重點是這個操作是可逆的, 不需要儲存任何額外的資訊。 因此對於需要儲存的資料量來說, 這是個可以提昇壓縮效果的「免費」操作, 只需要花費一些額外的計算。
使用於 bzip2。
範例:
輸入( |
代表 EOF)
^BANANA|
建立所有順序轉換
^BANANA|
|^BANANA
A|^BANAN
NA|^BANA
ANA|^BAN
NANA|^BA
ANANA|^B
BANANA|^
用字典順序排列
ANANA|^B
ANA|^BAN
A|^BANAN
BANANA|^
NANA|^BA
NA|^BANA
^BANANA|
|^BANANA
取出最後一行作為輸出
BNN^AA|A
逆操作(不斷地向前一行插入並排序):
B A BA AN BAN ANA BANA
N A NA AN NAN ANA NANA
N sort A add NA sort A| add NA| sort A|^ add NA|^
^ ------> B -----> ^B ------> BA -----> ^BA ------> BAN -----> ^BAN
A N AN NA ANA NAN ANAN
A N AN NA ANA NA| ANA|
| ^ |^ ^B |^B ^BA |^BA
A | A| |^ A|^ |^B A|^B
ANAN BANAN ANANA BANANA ANANA|
ANA| NANA| ANA|^ NANA|^ ANA|^B
sort A|^B add NA|^B sort A|^BA add NA|^BA sort A|^BAN
------> BANA -----> ^BANA ------> BANAN -----> ^BANAN ------> BANANA
NANA ANANA NANA| ANANA| NANA|^
NA|^ ANA|^ NA|^B ANA|^B NA|^BA
^BAN |^BAN ^BANA |^BANA ^BANAN
|^BA A|^BA |^BAN A|^BAN |^BANA
BANANA| ANANA|^ BANANA|^ ANANA|^B
NANA|^B ANA|^BA NANA|^BA ANA|^BAN
add NA|^BAN sort A|^BANA add NA|^BANA sort A|^BANAN
-----> ^BANANA ------> BANANA| -----> ^BANANA| ------> BANANA|^
ANANA|^ NANA|^B ANANA|^B NANA|^BA
ANA|^BA NA|^BAN ANA|^BAN NA|^BANA
|^BANAN ^BANANA |^BANANA ^BANANA|
A|^BANA |^BANAN A|^BANAN |^BANANA
輸出以「EOF」結尾的那一列:
^BANANA|
範例 Python 程式:
def bwt(s):
n = len(s)
table = [s[n-i:]+s[:n-i] for i in range(n)]
table.sort()
return ''.join(t[-1] for t in table)
def reverse_bwt(s):
l = [c for c in s]
l.sort()
for _ in range(len(s)):
l = [i+c for c, i in zip(l, s)]
l.sort()
for i in l:
if i[-1] == "|":
return i
if __name__ == '__main__':
print(bwt("^BANANA|"))
print(reverse_bwt("BNN^AA|A"))
更有效率的作法:
TODO