概述
字首編碼,有時也被稱為前向編碼,是另一個通過移除冗餘資料來降低資料量的演算法。思想非常簡單,但演算法實現比較困難。要了解原因,首先我們來看一看它的原理。
請看下面的字典。
1 2 3 4 5 6 7 8 |
use used useful usefully usefulness useless uselessly uselessness |
為了不使用純文字儲存這些單詞或者在網路上傳輸,我們可以用字首編碼進行壓縮(編碼)。
很明顯,每一個單詞都以表中的第一個單詞“use”為字首。所以我們很容易將它們壓縮成下面的陣列。
1 2 3 4 5 6 7 8 9 |
$data = array( 0 => 'use', 1 => '0d', 2 => '0ful', 3 => '0fully', 4 => '0less', 5 => '0lessly', 6 => '0lessness', ); |
顯然這並不是最佳的壓縮結果,在不僅僅使用第一個詞作為字首的情況下,我們可以更進一步壓縮。
1 2 3 4 5 6 7 8 9 |
$data = array( 0 => 'use', 1 => '0d', 2 => '0ful', 3 => '2ly', 4 => '0less', 5 => '4ly', 6 => '4ness', ); |
此時的壓縮更好,好訊息是解碼是一個相對簡單的過程。但棘手的部分在於壓縮本身。問題是選擇合適的字首非常困難。第一個例程的字首選擇很簡單,但事實上,大多時候資料很混亂。的確,對於隨機產生的資料壓縮過程將非常困難,演算法過程不僅很慢,而且難以實現。
好的方面是,如果我們事先知道資料的格式,該演算法可以用於多種情況。那麼,讓我們看看下面三個例子,該演算法可能會很方便。
應用
以下是三個字首編碼的例子。前面我說隨機資料的壓縮過程會很難,如果你事先知道輸入資料的格式,這將會是一個很好的練習。
日期和時間字首
我們通常會忽略年份的前兩個數字,例如我們通常不會寫1995或1996,而是使用更短的——‘95’和‘96’。這樣年份就被編碼成更短的字串。
1 2 |
input: (1991, 1992, 1993, 1994, 1995, 1996) output: (91, 92, 93, 94, 95, 96) |
問題在於輸入流發生很小的變動,解碼就會出錯。如果我們加上21世紀的年份,我們將失去資料的唯一性。
1 2 |
input: (1998, 1992, 1999, 2011, 2012) output: (98, 92, 99, 11, 12) |
此時,解碼器肯會將最後兩個數值解碼成(1911, 1912),因為“19”被認為是字首。所以,我們事先必須知道字首與每一個數值絕對平等。如果沒有編碼格式,必須不同。例如我們可以使用一些特殊標識和字首一起編碼。
1 2 |
input: (1998, 1992, 1932, 1924, 2001, 2012) output: (#19, 98, 92, 32, 24, #20, 01, 12) |
一旦解碼器讀到#字元,它就知道下面的數為字首。
事實上,這種方法可用於日期和時間格式的編碼。假設我們有一些日期時間值,而且我們知道所有資料都是在同一天。
1 2 3 4 |
2012-01-31 15:33:45 2012-01-31 16:12:11 2012-01-31 17:32:35 2012-01-31 18:54:34 |
顯然,我們可以忽略這些字串的時間部分,僅傳送(儲存)時間。當然,我們必須確定所有的這些數值都是在同一天。如果不是,我們可以使用上例中的方法。
電話號碼
電話號碼是字首編碼的典型應用。不僅僅是國際程式碼,行動網路運營商的電話號碼也使用字首編碼。如果我們要傳輸電話號碼,假設是英國的,我們可以用一些更短的東西替換開頭的“+44”。
如果你要給移動裝置編寫電話簿,你可以通過字首編碼壓縮資料,節省部分空間,這樣使用者將擁有更多空間,也可以在手機上儲存更多電話號碼。
電話號碼字首也適用於資料庫標準化。這樣你可以將它們儲存在單獨的資料庫表中,不用電話簿中唯一的號碼。
地理座標
對於我之前帖子中使用的例子,可以在一定範圍內去掉通用字首來傳送地理座標。的確,在必須傳送大量座標到地圖應用時,你可以預期這些標記在一定範圍內彼此間相當靠近。
在一定範圍內,可以預期這些標記都有相同的字首。
那些點的座標有共同的字首,就像下面地鐵站的例子一樣。
1 2 3 4 |
LatLon(40.762959,-73.985989) LatLon(40.761886,-73.983629) LatLon(40.762861,-73.981612) LatLon(40.764616,-73.98056) |
我們可以發現所有的地理座標點有相同的字首(40.76x, -73.98x),所以我們只需要傳送一次字首。
1 2 3 4 5 6 |
Prefix: (40.76, -73.98) Data: LatLon(2959,5989) LatLon(1886,3629) LatLon(2861,1612) LatLon(4616,056) |
以上是字首編碼的三個例子,該演算法在傳輸均勻資料是非常有用。
字尾編碼
字尾編碼和字首編碼幾乎相同,區別在於編碼重複字尾。如下例,字尾編碼替換最後重複的字尾,這非常有用。
1 2 3 |
Johnson Clarkson Jackson |
或者公司名稱。
1 2 3 |
Apple Inc. Google Inc. Yahoo! Inc. |
這裡我們可以使用一些其他更短的東西來替換“Inc”。