BurrowsWheeler 普林斯顿 算法第四版
文章目录
前言
总算是完成这一个课程的所有作业了,开心撒花。
本次作业的spec:
https://coursera.cs.princeton.edu/algs4/assignments/burrows/specification.php
FAQ(Frequently Asked Questions):
https://coursera.cs.princeton.edu/algs4/assignments/burrows/faq.php
提示:以下是本篇文章正文内容,下面案例可供参考
一、作业要求
本次作业需要完成Burrows-Wheeler 数据压缩算法。该算法包含三个部分:
- Burrows-Wheeler 变换。
- Move-to-front编码。
- Huffman(霍夫曼)压缩。
其中第三个部分Huffman(霍夫曼)压缩不需要我们实现。
二、功能分析与代码
按照作业推荐的顺序,前后实现
- CircularSuffixArray.java
- BurrowsWheeler.java
- MoveToFront.java
1. CircularSuffixArray.java
首先是分析,然后是代码
(1)分析与实现
作业的hits中提到:
- 确保不要创建新对象
- 定义一个CircularSuffix类来隐式表示CircularSuffixArray
- 考虑使得CircularSuffix类implement Comparable<CircularSuffix>接口
以上图输入的字符串为 "ABRACADABRA!"为例子
- 首先考虑Original Suffixes,采用一个数组(名为sortSuffixes)来存储每一个original suffixes的向左的位移量。即i=0时,sortSuffixes[i]=0;i=1时,sortSuffixes[i]=1。
sortSuffixes = new Integer[length()];//
for (int i = 0; i < length(); i++)
sortSuffixes[i] = i;
- 随后写一个函数(SuffixesOrder)implements Comparator的接口,重写compare函数。此时根据sortSuffixes的下表,隐式的将每个i下的orignial suffixes建立并比较排序。排序的规则是,依次比较 位移量取模 位置的字符(使用charAt)。最终获得排序的数组(名为sortSuffixes)。排序后index[i]就等于sortSuffixes[i]。
private class SuffixesOrder implements Comparator<Integer> {
//主要关注字符串相等情况
public int compare(Integer a, Integer b) {
//if ((length() - 1) < i) return 1;//
//else if ((length() - 1) < j) return -1;//
for (int i = 0; i < length(); i++) {
char c1 = string.charAt((i + a) % length());
char c2 = string.charAt((i + b) % length());
if (c1 > c2) return 1;
if (c1 < c2) return -1;
}
return 0;
}
}
2. BurrowsWheeler.java
该部分要实现 transform() 和 inverseTransform()
(1)transform() 的分析与实现
这个函数的意思是输入"ABRACADABRA!" 数组,我们要输出图片中蓝色的 “3” 以及 t 字符串。 3 代表 “ABRACADABRA!” 在sorted Suffixes的第 3 行。
- 根据要求,调用先前的CircularSuffixArray,当index[i]==0时,当前的i即为first
- 遍历index[i], 找到输入字符串(ABRACADABRA!)中的第index[i]个字符即为当前 i th中输出的字符
public static void transform() {
StringBuilder input = new StringBuilder();
while (!BinaryStdIn.isEmpty()) {
input.append(BinaryStdIn.readChar());
}
// String input = BinaryStdIn.readString();
CircularSuffixArray arr = new CircularSuffixArray(input.toString());
//find first
int length = arr.length();
for (int i = 0; i < length; i++) {
if (arr.index(i) == 0) {
//first = i;
BinaryStdOut.write(i);
break;
}
}
//find t
for (int i = 0; i < length; i++) {
int tmp = arr.index(i);
int lastIndex = (length - 1 + tmp) % length;
BinaryStdOut.write(input.charAt(lastIndex));
}
BinaryStdOut.close();
}
(2)inverseTransform()的分析与实现
该函数要求输入t[]字符串和first,输出next[],最终按照next输出原始字符串。
这个函数的实现较为困难,但实际上实现起来很简单。FAQ里提示我们使用key-indexed counting 算法来实现,该算法的演示如下图所示。
- 使用count[]将t中的字符按字符序计数,并累加
- 构建next[]。依次读入t[],并按照算法规则有序放置在next[i]。 可以发现读入t[]的第 i th存入next[]。如t[]中第一个读入的"A",根据算法会被放置在i=0的位置,即next[1]=0;而如t[]中第二个读入的"R",根据算法会被放置在i=11的位置,即next[11]=1。
- 构建orgin[]。为了输出原始字符串我们在记录next[]的同时,记录origin[]。如t[]中第一个读入的"A",根据算法会被放置在i=0的位置,即origin[1]=‘A’;而如t[]中第二个读入的"R",根据算法会被放置在i=11的位置,即origin[11]=‘R’。
- 输出原始字符串。根据first的位置,输出origin[first],并将first=next[first],反复操作,即可输出原始字符串。
3. MoveToFront.java
MoveToFront较为简单,这里采用LinkedList数据类型建立有序序列,通过该数据类型的接口可以较方便的实现有序序列的移除和向前移动。
public static void encode() {
LinkedList<Character> sequence = new LinkedList<>();
//char[] aux = new char[R];
for (int i = 0; i < R; i++)
sequence.add((char) i);
StringBuilder input = new StringBuilder();
while (!BinaryStdIn.isEmpty()) {
input.append(BinaryStdIn.readChar());
}
// StdOut.println(input);
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
//StdOut.printf("%c", c);
char index = (char) sequence.indexOf(c);
BinaryStdOut.write(index);
sequence.remove((Object) c);
sequence.addFirst(c);
}
BinaryStdOut.close(); // out.close();
}
public static void decode() {
LinkedList<Character> sequence = new LinkedList<>();
//char[] aux = new char[R];
for (int i = 0; i < R; i++)
sequence.add((char) i);
StringBuilder input = new StringBuilder();
while (!BinaryStdIn.isEmpty()) {
input.append(BinaryStdIn.readChar());
}
// StdOut.println(input);
for (int i = 0; i < input.length(); i++) {
int c = (int) input.charAt(i);
//StdOut.printf("%c", c);
char index = sequence.get(c);
BinaryStdOut.write(index);
sequence.remove((Object) index);
sequence.addFirst(index);
}
BinaryStdOut.close(); // out.close();
}
总结
该作业最终获得了100/100