(注:本文大多數內容摘自中文/英文維基百科)
一.什麼是BWT算法?
Burrows–Wheeler變換(BWT,也稱作塊排序壓縮),是一個被應用在數據壓縮技術(如bzip2)中的算法。該算法於1994年被Michael Burrows和David Wheeler在位於加利福尼亞州帕洛阿爾託的DEC系統研究中心發明。它的基礎是之前Wheeler在1983年發明的一種沒有公開的轉換方法。
當一個字符串用該算法轉換時,算法只改變這個字符串中字符的順序而並不改變其字符。如果原字符串有幾個出現多次的子串,那麼轉換過的字符串上就會有一些連續重複的字符,這對壓縮是很有用的。該方法能使得基於處理字符串中連續重複字符的技術的編碼更容易被壓縮。
舉個栗子:
input:SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES
output:TEXYDST.E.IXXIIXXSSMPPS.B..E.S.UESFXDIIOIIIT
該算法的輸出因爲有更多的重複字符而更容易被壓縮了,例如使用遊程編碼:Run-length encoding。
二.變換過程
2.1 對原文本轉碼
簡單來講,就是a)循環移位生成矩陣,b)對矩陣中的行按字典序排序,c)輸出最後一列得到變換結果。直接上栗子
input:^BANANA|
其中^和|分別標記字符串的頭和尾。
實現過程:
//encode過程
//樸素的方法,即:輪轉構造矩陣->排序->輸出矩陣最後一列
public String enCode(String line) {
String str = line;
int len = str.length();
// 1.輪轉
char[] charArray = str.toCharArray();
char[][] ch = new char[len][len];//矩陣
for (int i = 0; i < len; i++) {
char[] c_tmp = charArray.clone();
for (int j = 0; j < len; j++) {
ch[i][j] = c_tmp[j];
if (j <= len - 2)
charArray[j + 1] = c_tmp[j];
}
charArray[0] = c_tmp[len - 1];
}
// 2.排序,按照字典順序
String[] strings = new String[len];
for (int i = 0; i < len; i++) {
StringBuffer chline = new StringBuffer();
for (char c : ch[i]) {
chline.append(c);
}
strings[i] = chline.toString();
}
Arrays.sort(strings);
// 3.取最後一行
StringBuffer sBuffer = new StringBuffer();
for (String s : strings) {
sBuffer.append(s.substring(len - 1, len));
}
return sBuffer.toString();
}
2.2 解碼過程
乍一看,一個普通的排序也能得到和BWT差不多效果的結果,其實不然。BWT的厲害之處就在於它還能對轉碼後的結果逆推回原文本。即解碼過程。
具體一點,先拿到轉碼結果,即轉碼矩陣中的最後一列。最後一列的意義在於,它告訴了你文本中含有的所有字符,所以對該列按字典序排序,然後把最後一列和排序結果接起來。形成了n行“一對”字符,這些“一對”字符就是原文本中所有的連續字符。再對這些“一對”字符排序,。按照這個規則,n次循環後,結束字符在結束位置的那一行就是原文本。舉慄來看:
實現過程:
//直接用字符串拼接做的輪轉,事實證明效率低下。
public String deCode(String source){
//字符串默認"|"作爲終止符
int len=source.length();
String result="";
StringBuffer []matrix=new StringBuffer[len];
StringBuffer tmp=new StringBuffer(source);
String []tmp1=new String[len];
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(i>0){
tmp=matrix[j];
matrix[j]=new StringBuffer();
matrix[j].append(source.charAt(j));
matrix[j].append(tmp);
}
else {
matrix[j]=new StringBuffer();
matrix[j].append(source.charAt(j));
}
}
for(int k=0;k<matrix.length;k++)
tmp1[k]=matrix[k].toString();
Arrays.sort(tmp1);
for(int k=0;k<matrix.length;k++){
matrix[k].delete(0, len-1);
matrix[k]=new StringBuffer(tmp1[k]);
}
}
for(StringBuffer st:matrix)
if(st.charAt(len-1)=="|".charAt(0))
result=st.toString();
return result;
}