BWT(Burrows-Wheeler Transformation)の説明とjava実装
7875 ワード
BWT(Burrows-Wheeler Transformation)
1.BWTとは
圧縮技術の主な仕事の方式は繰り返しのモードを見つけて、緊密な符号化を行うことです.
BWT(Burrows–Wheeler_transform)は、元のテキストを類似のテキストに変換し、変換後、同じ文字位置が連続的または隣接するようにし、その後、Move-to-front transformおよびコースコードなどの他の技術を使用してテキスト圧縮を行うことができる.
2.BWTの原理
2.1 BWT符号化
(1)まず,BWTはまず変換が必要なテキストブロックを右回りにループし,1ビットずつループする.長さ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)に移動します.
ソート後の文字列BWT変換後の文字列
まずBWT変換後の文字列にドル記号「$」を見つけ、同じ行のアルファベットがBであることを書きます.$BがBを見つけた後、右の欄でBを探します.それに対応するのはAです.
そして$BAをメモして、
今Aのは左で3回目の出現で、だから右の1欄の中でAを探して、同じく3回目の出現で、それに対応するのはNで、それから$BANをメモして、左のN
2回目の出現なので、右の欄でNを探すのは同じように2回目の出現で、それに対応するのはAで、
それから$BANAをメモして、今Aの左側は2回目の出現で、だから右側で、1欄の中でAを探して同様に2回目の出現で、それに対応するのはNで、それから$BANANをメモします
左のNは初めてなので、右の欄でNを探すのも初めてですが、
これに対応するのはAで、それから$BANANAをメモして、今のAは左側で初めて現れたので、右の欄でAを探すのは同じように初めて現れたので、それに対応するのは「$」で、終わります.
1.BWTとは
圧縮技術の主な仕事の方式は繰り返しのモードを見つけて、緊密な符号化を行うことです.
BWT(Burrows–Wheeler_transform)は、元のテキストを類似のテキストに変換し、変換後、同じ文字位置が連続的または隣接するようにし、その後、Move-to-front transformおよびコースコードなどの他の技術を使用してテキスト圧縮を行うことができる.
2.BWTの原理
2.1 BWT符号化
(1)まず,BWTはまず変換が必要なテキストブロックを右回りにループし,1ビットずつループする.長さ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)に移動します.
ソート後の文字列BWT変換後の文字列
まずBWT変換後の文字列にドル記号「$」を見つけ、同じ行のアルファベットがBであることを書きます.$BがBを見つけた後、右の欄でBを探します.それに対応するのはAです.
そして$BAをメモして、
今Aのは左で3回目の出現で、だから右の1欄の中でAを探して、同じく3回目の出現で、それに対応するのはNで、それから$BANをメモして、左のN
2回目の出現なので、右の欄でNを探すのは同じように2回目の出現で、それに対応するのはAで、
それから$BANAをメモして、今Aの左側は2回目の出現で、だから右側で、1欄の中でAを探して同様に2回目の出現で、それに対応するのはNで、それから$BANANをメモします
左のNは初めてなので、右の欄でNを探すのも初めてですが、
これに対応するのはAで、それから$BANANAをメモして、今のAは左側で初めて現れたので、右の欄でAを探すのは同じように初めて現れたので、それに対応するのは「$」で、終わります.
package cn.genekang.io.test;
import java.util.Arrays;
public class BWTtest {
public static void main(String[] args) {
String str = "banana";
System.out.println(" :"+str);
String enCodeStr = enCode(str);
System.out.println(" :"+enCodeStr);
System.out.println(" :"+deCode(enCodeStr));
}
// bwt
public static 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();
}
// bwt
public static String deCode(String str) {
int len = str.length();
String[] strArr = new String[len];
for (int i = 0; i < len; i++) {
strArr[i] = str.substring(i, i + 1) + ":" + i;
}
Arrays.sort(strArr);
// for(String string : strArr)
// System.out.println(string);
StringBuffer sb = new StringBuffer();
int num = 0;
int corr = Integer.parseInt(strArr[0].split(":")[1]);
while (num < len-1) {
sb.append(strArr[corr].split(":")[0]);
corr =Integer.parseInt( strArr[corr].split(":")[1]);
num++;
}
return sb.toString();
}
}