1. 程式人生 > >BWT (Burrows–Wheeler_transform)數據轉換算法

BWT (Burrows–Wheeler_transform)數據轉換算法

== 第一個 字符數 ans ons 子串 tar ntp rom

轉自:http://www.cnblogs.com/xudong-bupt/p/3763814.html

具體分析見:http://blog.csdn.net/windroid/article/details/50570450

1.什麽是BWT

  壓縮技術主要的工作方式就是找到重復的模式,進行緊密的編碼。

  BWT(Burrows–Wheeler_transform)將原來的文本轉換為一個相似的文本,轉換後使得相同的字符位置連續或者相鄰,之後可以使用其他技術如:Move-to-front transform遊程編碼 進行文本壓縮。

2.BWT原理

2.1 BWT編碼

  (1)首先,BWT先對需要轉換的文本塊,進行循環右移,每次循環一位。可以知道長度為n的文本塊,循環n次後重復,這樣就得到看n個長度為n的字符串。如下圖中的“Rotate Right”列。(其中‘#’作為標識符,不在文本塊的字符集中,這樣保證n個循環移位後的字符串均布相同。並且定義‘#‘小於字符集中的任意字符)。

   (2)對循環移位後的n個字符串按照字典序排序。如下圖中的“Sorted (M)”列。

   (3)記錄下“Sorted (M)”列中每個字符串的最後一個字符,組成了“L”列。(其中"F"列是“Sorted (M)”列中每個字符串的前綴)

技術分享

  這樣,原來的字符串“banana#”就轉換為了“annb#aa”。在某些情況下,使用L列進行壓縮會有更好的效果。“L”列就是編碼的結果。

2.2 BWT解碼

  因為進行的是循環移位,且是循環左移註意下面的性質:

  1、L的第一個元素是Text中的最後一個元素   2、對於M中的每一行(第一行除外)第一個元素都是最後一個元素的下一個元素。
     也就是說,對於文本塊而言,同一行中F是L的下一個元素,L是F的前一個元素。   這樣,就需要   (1)通過"F"列中的元素,找到他前面的字符,就是對應的同一行“L”列;   (2)通過“L”列中的元素,找到他在“F”列中的對應字符位置。但是“L”中有3個字符a,如何對應F中的3個a呢?因為L是F的前一個元素,多個具有相同前綴的字符串排序,去掉共同前綴後相對次序沒有變化。所有遇到多個相同的字符,相對位置不變;   (3)轉到(1),直到結束。 技術分享   因為F列是已經排序的,可以從L列獲得,所有只需要保存L列就可以。從L列中的字符獲取在F列中的位置時,需要:   (1)前綴和數組,記錄小於當前字符的字符數個數。   (2)count計數,計算L中從開始位置到當前字符位置等於該字符的字符數。(保證多個相同字符下"L"到“F”的相對位置不變)。

3.BWT文本塊編碼、解碼實例

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <string.h>
 5 using namespace std;
 6 
 7 ///編碼,生成last數組
 8 int getLastArray(char *lastArray,const string &str){    ///子串排序
 9     int len=str.size();
10     string array[len];
11 
12     for(int i=0;i<len;i++){
13         array[i] = str.substr(i);
14     }
15     sort(array,array+len);
16     for(int i=0;i<len;i++){
17         lastArray[i] = str.at((2*len-array[i].size()-1)%len);
18     }
19     return 0;
20 }
21 
22 int getCountPreSum(int *preSum,const string &str){
23     memset(preSum,0,27*sizeof(int));
24     for(int i=0;i<str.size();i++){
25         if(str.at(i) == ‘#‘)
26             preSum[0]++;
27         else
28             preSum[str.at(i)-‘a‘+1]++;
29     }
30 
31     for(int i=1;i<27;i++)
32         preSum[i] += preSum[i-1];
33     return 0;
34 }
35 
36 ///解碼,使用last數組,恢復原來的文本塊
37 int regainTextFromLastArray(char *lastArray,char *reGainStr,int *preSum){
38     int len=strlen(lastArray);
39     int pos=0;
40     char c;
41     for(int i=len-1;i>=0;){
42         reGainStr[i] = lastArray[pos];
43         c = lastArray[pos];
44         pos = preSum[c-‘a‘]+count(lastArray,lastArray+pos,c);
45         i--;
46     }
47     return 0;
48 }
49 
50 int main (){
51     string str("sdfsfdfdsdfgdfgfgfggfgdgfgd#");
52     int preSum[27];
53     int len=str.size();
54 
55     char *lastArray = new char[len+1];
56     char *reGainStr = new char[len+1];
57     lastArray[len]=‘\0‘;
58     reGainStr[len]=‘\0‘;
59 
60     getCountPreSum(preSum,str);
61     getLastArray(lastArray,str);
62     regainTextFromLastArray(lastArray,reGainStr,preSum);
63 
64     cout<<"       str: "<<str<<endl;
65     cout<<"lastArray : "<<lastArray<<endl;
66     cout<<"reGainStr : "<<reGainStr<<endl;
67 
68     delete lastArray;
69     delete reGainStr;
70     return 0;
71 }

  

代碼執行輸出:

技術分享

參考:

http://en.wikipedia.org/wiki/Burrows%E2%80%93Wheeler_transform

http://emily2ly.iteye.com/blog/742869

額外閱讀:

MTF(Move-to-front transform)數據轉換

基於統計的壓縮算法:遊程編碼

BWT (Burrows–Wheeler_transform)數據轉換算法