Programming Assignment 5: Burrows–Wheeler Data Compression

Programming Assignment 5: Burrows–Wheeler Data Compression

1. 题目阅读

实现Burrows-Wheeler数据压缩算法。这个革命性的算法产生了gzip和pkzip,并且相对容易实现,还不受任何专利保护。它构成了unix压缩实用程序bzip2的基础。

这个算法由以下三种算法组成:

  1. Burrow-Wheeler变换。Given a typical English text file, transform it into a text file in which sequences of the same character occur near each other many times.(Google翻译:给定典型的英文文本文件,将其转换为文本文件,其中相同字符的序列在彼此附近多次出现。)

    这里读英文没读懂,然后去搜索了一下。**这个变换不会改变字符,但是会改变字符串的顺序,它将字符串中相似的字串移动到附近。**在wiki找到个例子,很形象,具体解释往下面继续看。见下表。

      
    算法输入SIX.MIXED.PIXIES.SIFT.SIXTY.PIXIE.DUST.BOXES
    算法输出TEXYDST.E.IXIXIXXSSMPPS.B..E.S.EUSFXDIIOIIIT
  2. Move-to-front编码。给定一个相同字串在附近的文本文件,将其转换为一个出现频率多的字串在前方的文本。

  3. Huffman压缩。给定一个出现频率多的字串

第三步是压缩信息的一步,因为第一步和第二步产生了一个某些字母比其他字母出现频繁的文本文件。为了解压这个文件,用相反的顺序操作,第一步,Huffman展开,然后move-to-front解码,最后Burrow-Wheeler逆变换。你的任务就是实现Burrow-Wheeler和move-to-front部分。

二进制输输出

为了让你的程序可以处理二进制数据,你需要使用算法第四版提供的 BinaryStdIn 和 BinaryStdOut。你可以使用 HexDump 在调试时来显示二进制输出。 HexDump 接受一个命令行参数n,从标准输入读取字节,并将其写入到16进制,每行k个十六进制数。

Huffman压缩和解压

使用书上提供的

Move-to-front编码和解码

move-to-front编码的主要想法是维护一个字符的顺序。重复从输入信息读取字符,打印出这个字符的位置,然后将这个字符移动到序列的前方。作为一个简单的例子,如果初始六个字符的顺序是A B C D E F,然后我们希望去编码输入CAAABCCCACCF,然后我们需要按照如下方法去更新move-to-front序列。

move-to-front_example

如果输入中相同的字母出现在相互附近许多次,那么许多输出值将为很小的证书,例如0,1和2。非常高频率的确切字母将是Huffman编码的理想场景。

  • Move-to-front编码。你的任务是维护一个包含256个字符的额外ASCII字符串。使用字符在编码中的顺序初始化字符串。然后从输入中每次读取一个8位字符,输出在字符串中的8位索引。当c出现过,就将c移动到字符串前面。
  • Move-to-front解码。和编码初始化相同的字符串,然后从输入中每次读取一个八位字符i,将字符串中第i个字符输出,并且移动到前面。

使用下面的api:

性能需求 编码解码时间最差为 ~(nR),在实践中为 ~(n + R)。内存最差为 ~(n + R)

Circular suffix array.

为了有效的实现Burrows-Wheeler变换中的关键部分,你需要使用一个被叫做 circular suffix array 的基础数据结构。这个数据结构描述了长度为n的字符串的n个循环后缀的排序数组的抽象。作为例子,我们考虑长度为12的字符串 "ABRACADABRA!"。下面的表格显示了他的12循环后缀和排序后的结果。

circular_suffix_array_example

我们定义了 index[i] 表示在排序后的数组中,每一行在原始数组中的位置。例如 index[11] = 2 ,表示原始数组中第二行后缀出现在了排序后数组的第11行。

实现下面的api,并提供 index[]

边界条件 参数args为null,index超出索引。抛出异常。

性能需求 典型的英语文本,空间 ~(n + R) 。构造函数 ~(nlogn) , length() 和 index() 常数时间。警告:在java7, Update 6中, substing() 方法使用与字串成比例的时间和空间,换句话说,你不能明确的形成一个 n 个重复后缀的字符串,因为这样会花费平方时间和空间。(为什么是平方??)

Burrows–Wheeler变换

Burrows–Wheeler变换的目标不是去压缩信息,而是将信息转换为更适合压缩的形式。变换将输入字符的顺序重新排列为许多有相同字符的集合,但是使用这种变换后的集合依然可以恢复原始输入的顺序。它取决于下面的直觉:当你在英文文本中看到 hen时,它前一个字母最可能为 t 或 w 。如果你能以某种方式将所有这些前面的字母组合起来,你会有一个简单的数据压缩的机会。

  • Burrows-Wheeler变换。对一个长度为n的字符串s的Burrows-Wheeler变换定义如下:

    考虑对s的n个循环后缀进行排序的结果,Burrows-Wheeler变换 t[] 是排序后缀的最后一列, first是原始字符串在的行。还是上面的例子,如下图。其中 first = 3t[] = ARD!RCAAAABB

    Burrows-Wheeler_example

    注意到里面有4个连续的A,2个连续的B.这些集合将很容易被压缩。

    % java-algs4 BurrowsWheeler - < abra.txt | java-algs4 edu.princeton.cs.algs4.HexDump  16
    00 00 00 03 41 52 44 21 52 43 41 41 41 41 42 42
    128 bits

    同样,整数3使用4个子节来表示(00 00 00 03)。字母 A 被表示为hex 41,字母 R 被表示为 52,其他的以此类推。

  • Burrows-Wheeler逆变换。现在我们来描述如何逆转Burrows-Wheeler变换,并恢复原始的输入字符串。如果 jth 原始后缀(将原始字符串向左移动j个字符串)是排序后数组的第 i 行,我们定义 next[i] 为 (j + 1)th 原始后缀在排序后数组的行数。例如,如果 first 是原始字符串所在的行,那么 next[first] 是 1st 原始后缀(将原始字符串向左移动1个字符串)在排序后数组的行数, next[next[first]] 是 2nd 原始后缀(将原始字符串向左移动2个字符串)在排序后数组的行数,以此类推。

    • 从给定的 t[], first 和 next[] 数组反推信息。Burrows-Wheeler解码器的输入是排序后的数组的最后一列 t[] 和 first。从 t[] 中我们可以推断出排序后缀数组的第一行,因为它和 t[] 有相同的字符,只不过是排序的。

      Burrows-Wheeler_inverse_example

      当给出 next[] 和 first 是,我们可以重构原始输入字符串。因为 ith 原始字符串的第一个字符是原始字符串的第 i 个字符。在上面的例子中,因为 first = 3, 所以我们知道原始字符串在第三行。因此,原始字符串从 A 开始,以 ! 结束。 因为 next[first] = 7,下一个原始字符串后缀出现在第七行,因此下一个原始字符串的字符是 B。因为 next[next[first]] = 11, 下一个原始字符串后缀出现在第11行,因此下一个原始字符串字符是 R

    • 从数组 t[] 和 first 构造数组 next[]。令人惊讶的是,重构这些信息的 next[] 包含在Burrows-Wheeler变换里,也就意味着原始信息也包含在其中。对于只出现过一次的字符,推断 next[] 是非常容易地。例如,考虑已 C 开头的后缀字符串。通过查看第一列,看出它在排列后数组的第8行,排在它后面的下一个后缀字符串将以 C 为结尾。通过查看最后一列,原始顺序的下一个后缀字符串在当前数组的第5行,所以 next[8] = 5。相似的 D 和 *!*也很好得出。

      Burrows-Wheeler_build_next_example

      然而,因为 R 出现了2次,next[10] = 1 和 next[4] = 4 或者 next[10] = 4 和 next[4] = 1 就变得含糊不清。 这里有一个关键的规则来解决模糊性。

      如果排序过的数组第i行和第j行由同样的字符开始,且 i < j,那么 next[i] < next[j]。

      这个规则意味着next[10] = 1 和 next[4] = 4。为什么这个规则有效呢?这些行都是被排序过的,也就意味着第10行比第11行字典顺序小,因此,剩下10个位置的字符构成的字符串,第10行的 也一定小于第11行。我们也知道在由 R 结尾的两行中,第1行小于第4行,因此next[10] = 1 和 next[4] = 4,否则这与后缀排序的事实相矛盾。

实现BurrowsWheeler类,使用以下api:

性能需求 变换的最差时间 ~(n + R),包括构造循环后缀数组。逆变换时间最差为 ~(n + R)。内存使用最差 ~(n + R)

2. 题目分析

这回题目对算法实施细节讲的很细。毕竟这个压缩方法课上也没讲。

具体实现MoveToFront, BurrowsWheeler, CircularSuffixArray这三个类。

MoveToFront

编码 这里需要将字符串中的某一个字符提到第一个,还需要查找某个字符在字符串的第几个位置。维护一个长度为R的字符数组,最开始就按照ascii填充。然后每次从头开始将前一个元素覆盖到后一个元素,直到找到匹配的字符,将此字符放到第一个,然后将上一个填充到此位置。

解码 同样维护一个字符数组,覆盖到要寻找的第i个。

CircularSuffixArray

构造函数 根据字符串s的位数n,生成n个后缀循环字符串,并在每个字符串最后加上一个表示左移位数的数,组成一个字符串数组,这个数不会影响字符串的排序,但是可以用来产生index。然后使用MSD对数组进行排序,使用排序后的字符串的最后一位生成index。不用生成t,一是可以通过index生成,二是api没有需求。

这里题目提示了,不能构造n个string,那样性能就是平方级了。可以在原始字符串上排序。使用了构造Array.sort()的比较器。从这里参考到这里。然后最优的方法是自己实现一个字符串的三向字符串快速排序。可以参考这里。

长度和index函数返回对应的东西就行。

BurrowsWheeler

编码 使用循环后缀数组,得到index,然后使用index产生 t[] ,t[i] = s 的第 index[i] - 1 位,若 i = 0,就是最后一位。同时记录 index[i] = 0 的 i,这个就是 first

解码 将二进制的流转换为 first 和 t[]。然后使用 t[] 去生成 next[]。最后使用 first, t[], *next[]*来转换为原信息。

逆变换排序要自己写key-index排序性能才能达标。

发现好像具体压缩的程序不需要自己实现。

转载于:https://www.cnblogs.com/huipengly/p/9884670.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hadoop Connection refused: no further information原因排查(Centos7)

一&#xff1a;排查防火墙&#xff0c;是否开放9000端口 firewall-cmd --list-ports查看防火墙是否有9000端口&#xff0c;如果没有&#xff0c;通过下面的命令添加端口&#xff1a; firewall-cmd --zonepublic --add-port9000/tcp --permanent systemctl restart firewalld…

[css]你有使用过preload、preconnect、prefetch这些属性吗?说说它们都有什么作用?

[css]你有使用过preload、preconnect、prefetch这些属性吗&#xff1f;说说它们都有什么作用&#xff1f; preload 元素的 rel 属性的属性值preload能够让你在你的HTML页面中元素内部书写一些声明式的资源获取请求&#xff0c;可以指明哪些资源是在页面加载完成后即刻需要的。…

elasticsearch 6.x (二) linux部署 kibana x-pack 安装

大家好&#xff0c;我是烤鸭&#xff1a; 环境&#xff1a;linux Cent OS 7.3elasticsearch-6.2.4 1. 下载elasticsearch https://www.elastic.co/downloads/elasticsearch 上面的网址直接下载的话&#xff0c;实在太慢了。官方还提供了另一种方式。 https://www.elastic.co…

Kali Linux ——在无网络情况下安装无线网卡驱动

1、背景&#xff1a; 今日刚刚开始学习kali linux&#xff0c;众所周知&#xff0c;安装完成后&#xff0c;系统是没有无线网卡驱动的&#xff0c;这就对学生党造成相当的困扰&#xff1a;校园网要连接有线是需要认证客户端的&#xff0c;而认证客户端只有windows端&#xff0c…

HADOOP_HOME and hadoop.home.dir are unset 报错处理

一般是windows才会出现这个问题 请看下面的解决方案&#xff1a; 第一步&#xff1a;下载winutils-master.zip Gitee地址&#xff1a;https://gitee.com/nkuhyx/winutils.git 蓝奏云&#xff1a;https://www.lanzoux.com/i55ccnc Github地址&#xff1a;https://github.com/cda…

[css] 你是怎样对css文件进行压缩合并的?

[css] 你是怎样对css文件进行压缩合并的&#xff1f; 使用在线网站进行压缩&#xff0c;如http://tool.lu/css如使用Gulp&#xff0c;可使用gulp-minify-css进行压缩如使用WebPack&#xff0c;可使用optimize-css-assets-webpack-plugin进行压缩个人简介 我是歌谣&#xff0c;…

elasticsearch 6.x (三) linux 集群多节点部署

大家好&#xff0c;我是烤鸭&#xff1a;关于集群内单个节点部署&#xff0c;请参考上一篇文章。elasticsearch 6.x linux部署(二) kibana x-pack 安装环境&#xff1a;linux Cent OS 7.3elasticsearch-6.2.41. 下载多个es安装每个安装步骤都是一样的。2. 修改配置文件(重…

ztree改变节点颜色

//找到节点对象 var node ztree.getNodesByParam("id",aaaaaaaaaabbbbbb, null)[0]; if(node!null){//找到span标签&#xff0c;并改变颜色$("#"node.tId"_span").css("color",red); }

版本下载地址

http://chromedriver.storage.googleapis.com/index.html转载于:https://www.cnblogs.com/nvhanzhi/p/9887999.html

[css] css3和css2的区别是什么?

[css] css3和css2的区别是什么&#xff1f; css3增加了更多特性&#xff1a;动画、过渡效果&#xff0c;圆角、文字特效等个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端…

springboot-devtools idea或eclipse 热加载

大家好&#xff0c;我是烤鸭&#xff1a;今天分享一下springboot项目的热加载。第二种方式在eclipse和idea中都可以。虽然会有一些小坑。 方式有两种&#xff1a; 1. springloaded(无效) <!-- https://mvnrepository.com/artifact/org.springframework/springloaded -->…

PostgreSQL创建数据库报错

ERROR:source database "template1"is being accessed by other users DETAIL:There are 2 other sessions using the database. 解决方案&#xff1a; CREATE DATABASE 数据库名称 WITH OWNER postgres ENCODING UTF8 TABLESPACE pg_default LC_COLLATE en_US.…

[css] 你知道什么是流体排版吗?说说它的原理是什么?

[css] 你知道什么是流体排版吗&#xff1f;说说它的原理是什么&#xff1f; 在文档流中&#xff0c;内联元素按内联方向显示&#xff0c;即词语在依据文件写作模式的句子中表示的方向。块元素则一个接一个地显示&#xff0c;就像该文档的写作模式中的段落一样。因此在流体排版…

java统计报表日期工具类

package com.test.common;import com.coyee.core.util.DateUtil;import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.*;/*** 时间工具类*/ public class DateUtils {/*<option value"today">今天</option><option valu…

springboot mybatis 热加载mapper.xml文件(最简单)

大家好&#xff0c;我是烤鸭: 今天介绍一下springboot mybatis 热加载mapper.xml文件。 本来不打算写的&#xff0c;看到网上比较流行的方式都比较麻烦&#xff0c;想着简化一下。 网上流行的版本。 https://www.cnblogs.com/oskyhg/p/8587701.html 总结一下需要&#xff1a;my…

vue cli vue 3.x

vue cli & vue 3.x https://cli.vuejs.org/dev-guide/ui-api.html#ui-api https://cli.vuejs.org/zh/guide/#cli vue cli & how to select the option in cmd ? vue cli & 选中 option a select all & i select all 1,2,3,4,5,6,7,8,9,0 分别对应 order 转载…

[css] 如果css文件过大时,如何异步加载它?

[css] 如果css文件过大时&#xff0c;如何异步加载它&#xff1f; 分割成多个CSS文件进行Gzip压缩link preload个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

jenkins svn/git sonarqube scanner 代码集成测试

大家好&#xff0c;我是烤鸭&#xff1a;今天分享一个代码检测工具sonar&#xff0c;在jenkins集成的时候使用。 环境:sonarqube 7.1jenkins 2.12xsonarqube scanner &#xff08;官网最新版3.2.0.1227&#xff09;1. jenkins svn/git 搭建项目https://blog.csdn.net/Angry…

[css] 你有使用过字体图标吗?它有什么好处?

[css] 你有使用过字体图标吗&#xff1f;它有什么好处&#xff1f; 代替图片&#xff0c;可以减少http请求次数&#xff0c;提高页面加载性能。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录…

Jqgried树形列表

**************************************Jqgrid树列表***************************************function initGrid_test() {//必要字段&#xff1a;id,name,level,parent,isLeaf,expandedvar topicjson{"response": [{"id": "1", "name&qu…