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,一经查实,立即删除!

相关文章

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…

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. 修改配置文件(重…

springboot-devtools idea或eclipse 热加载

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

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 转载…

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…

射频与微波测量之S参数

转自&#xff1a;https://www.cnblogs.com/lyh523329053/p/9128577.html S参数 S散射也叫散射参数。是微波传输中的一组重要参数。由于我们很难在高频率时测量电流或电压&#xff0c;因此我们要测量散射参数或 S 参数。这些参数用来表征RF 元件或网络的电气属性或性能&#xff…

JAVA构造对象的几种方式(构建器、构造器)

大家好&#xff0c;我是烤鸭&#xff1a;今天说一下初始化对象的几种方式&#xff1a;1. 多参数构造器2. 构建器3. 构造器后 get/set方法举个例子:这里有个机构entity&#xff0c;提供一个默认构造器 package com.xxx.xxx.modules.sys.entity;/*** 机构Entity* versi…

Django框架(十二)-- Djang与Ajax

一、什么是Ajax AJAX&#xff08;Asynchronous Javascript And XML&#xff09;翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互&#xff0c;传输的数据为XML&#xff08;当然&#xff0c;传输的数据不只是XML,现在更多使用json数据&#xf…

javascript 将table导出 Excel ,可跨行跨列

原文地址&#xff1a;https://www.cnblogs.com/hailexuexi/p/10795887.html <script language"JavaScript" type"text/javascript">//jQuery HTML导出Excel文件(兼容IE及所有浏览器)function HtmlExportToExcel(tableid,file_name) {var filename fi…

wampserver 搭建 php环境 运行方法

大家好&#xff0c;我是烤鸭&#xff1a;今天分享的是如何用wamp 运行 php代码。1. wampserver下载&#xff1a;下载地址&#xff1a;https://sourceforge.net/projects/wampserver/files/WampServer%203/WampServer%203.0.0/Addons/Php/wampserver3_x64_addon_php7.2.7.exe…

java php des加密 byte数组16进制 DESTools

大家好&#xff0c;我是烤鸭:今天分享的是java 和 php des 加密。因为接口对接&#xff0c;难免不同语言&#xff0c;加密又是必不可少的。作为接口的提供方&#xff0c;必须把加密规则写好&#xff0c;最好有不同语言的加密demo。1. java版本的des加密解密工具类DESTools.j…

高可用Eureka注册中心配置说明(双机部署)

目 录 1. 高可用EureKa注册中心示意图 2. Eureka实例相互注册配置 3. 微服务注册到Eureka配置 4. 启动步骤及配置成功检查 5. 说明事项 1. 高可用EureKa注册中心示意图 Spring Cloud的Eureka Server的高可用实际上就是将自己作为服务向其他服注册中心注册自己&#xff0c;形成…

java 实现 常见排序算法(一) 冒泡排序

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享一下基础排序算法之冒泡排序。 1. 冒泡排序&#xff1a; 原理&#xff1a;比较两个相邻的元素&#xff0c;将较大的元素交换至右端。 思路&#xff1a;依次比较相邻的两个数&#xff0c;将小数放在前面&#xff0c;大…

vue学习之npm

任何一门计算机语言都包含了丰富的第三方库&#xff0c;npm就是JavaScript这门语言的第三方库管理工具&#xff0c;本文详细介绍了JavaScript的包管理工具&#xff0c;npm。 在计算机中安装好Node.js之后&#xff0c;默认已经安装好了npm包管理工具&#xff0c;我们可以输入npm…

Java 深copy 浅copy 引用copy

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享一下浅copy和深copy。 1. 深copy 什么是深copy&#xff0c;只复制原对象属性值&#xff0c;不管地址。 说一下业务场景&#xff1a; 如果我想创建一个对象&#xff0c;只是对原对象的某个属性值改变。普通的做法就是new 一个…

linux定时任务清理cache缓存

大家好&#xff0c;我是烤鸭&#xff1a; 如果你出现类似cache过多的情况&#xff0c;请参考这篇。 buff/cache 占了1.6G&#xff0c;多数情况下是无所谓的。但是有时候在系统内存不足的时候&#xff0c;可能会影响其他程序的执行。 之前就遇到过 jenkins 因为内存不足 集成失败…

SecureCRT Application 已停止工作

解决方法一&#xff1a; cmd ----> regedit —>HKEY_LOCAL_MACHINE\SOFTWARE\vandyke 删掉vandyke 解决方法二&#xff1a; SecureCRT使用过程中出现异常后自动关闭&#xff0c;导致下次无法正常启动&#xff08;运行程序无反应&#xff09;&#xff0c;此时一种可能的原…