BurrowsWheeler 普林斯顿 算法第四版

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 数据压缩算法。该算法包含三个部分:

  1. Burrows-Wheeler 变换。
  2. Move-to-front编码。
  3. Huffman(霍夫曼)压缩。

其中第三个部分Huffman(霍夫曼)压缩不需要我们实现

二、功能分析与代码

按照作业推荐的顺序,前后实现

  • CircularSuffixArray.java
  • BurrowsWheeler.java
  • MoveToFront.java

1. CircularSuffixArray.java

首先是分析,然后是代码

(1)分析与实现

作业的hits中提到:

  • 确保不要创建新对象
  • 定义一个CircularSuffix类来隐式表示CircularSuffixArray
  • 考虑使得CircularSuffiximplement 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
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值