Managing Gigabytes--文本压缩

开门见山,文本压缩可以归纳为两大类, 符号方法和字典方法, 下面分别介绍下:


1)符号方法,symbolwise method
普通编码方式是每个字符都采用相同位数编码, 比如asc码, 每个字符都是8位编码。
那么现在要压缩,就是要用更少的位数来表示字符。显而易见, 我们只须用较小的位数来表示高概率字符, 用较长的位数来表示低概率字符,这样平均下来就可以实现压缩。


那么这里面就有两个点:
a)怎么来确定每个待编码字符的概率,这就是概率模型问题。
所谓概率模型就是为编码器提供的概率分布函数,我们必须保证编码器,和解码器使用相同的模型, 不然解出来的就不对了。
那么对于一个符号的编码位数是有个下限的, 和这个符合的信息量I(s)相关。
I(s)= -logPr[s] (Pr[s]就是s符合出现的概率)
所以对于”掷硬币面向上“这个事实,至少要用-log(1/2)=1位来编码。
那么对于字母表中每个符合的平均信息量称为”概率分布的熵(entropy)“, H = sum(Pr[s]*I[s])
假定符合以假设的概率值独立出现,H为压缩下限。即这是个理论极值,实际上不可能达到。
这也就是Claude Shannon著名的编码原理。

回到模型,可分为每个字符都当独立的符号来处理的0阶模型和仅考虑有限个前驱符号的m阶有限上下文模型。
也可分为静态模型, 半静态模型, 和自适应模型。
静态模型就是不考虑正在编码的文本,只使用固定的模型,这个模型就适用于文本模式相对固定的任务。
半静态模型就先为要压缩的文件生成模型, 发送给解压方, 这个方法需要遍历两遍被压缩的文档, 所以这个solution明显不太好。
所以比较流行的是自适应模型,adaptive modeling,即以平缓的概率模型开始, 随着遇到的符号变多, 不断的调整。
自适应模型往往要解决零频问题,这个问题解决方法很多, 最简单的是默认每个字符在刚开始时已出现过一次。
这种模型的缺点是不能对文本进行随机访问, 必须从文本的开头开始解码,因为我们必须保证编码和解码时的context是相同的。

对于怎么建立符号概率模型, 也是有很多研究, 比如部分匹配模型(Prediction by Partial Matching, PPM)依据以前的字符做出预测, 动态马尔可夫模型基于有限状态机。
这些模型就不详细描述了, 有兴趣可以参看相关文献。

b)知道待编码字符的概率,怎么给它分配合适的编码, 这就是编码算法的问题。

哈夫曼编码
介绍编码算法当然先来看看哈夫曼编码, 这个号称是作者在研究生时为了避免参加科目考试而想出的算法,很简单也很高效。再一次对美国的教育环境表示深深的敬意和向往。
这类算法基本想法就是给高概率字符分配较少位数的编码。
这就有个问题, 如果每个字符的编码位数不一样, 那么我们怎么知道后一个字符的编码位数,肯定不能用个len去指定。
哈夫曼的方法是解决编码前缀的歧义性(ambiguity), 即前缀编码,就是说每个编码的前缀都是不同的
那么怎么去产生编码和怎么去解码呢?
哈夫曼树,通过哈夫曼树,从下到上进行编码, 从上到下进行解码。具体怎么构建哈夫曼树, 就不具体说了, 很简单。
再一次感叹此算法构思的巧妙和简单。
对于静态的概率分布, 哈夫曼算法是很好的, 但对于自适应模型,哈夫曼算法会耗费较多的内存或时间。
因为自适应模型在同一时间会使用许多不同的概率分布,依赖于被编码文本的上下文的不同。那么这样就要同时建立多颗哈夫曼树。

 

算术编码

那么对于自适应模型而言算术编码更受欢迎。
算术编码相对比较复杂,不过显著的优势是算术编码可以用低于一位的编码来表示高概率字符, 而哈夫曼编码对于每个字符至少要用一位来编码。
由于算术编码包含了各种不同的概率分布, 所以比较适合自适应模型。
但对于静态模型,还是哈夫曼编码要快许多。

算术编码的基本思想就是, 在编码过程中, 随着各个字符的出现不断缩小概率区间, 高概率字符不会大幅地缩短区间,而低概率字符会导致产生一个小的多的‘下一个’区间。
算术编码只有当编码完成时,才会一次性输出编码,编码值就是在最终的概率区间内任意选取一个值,区间越小,表示这个值所用的位数越多。
不好理解,就举个例子:
对于只有3个字符的字符集a,b,c, 对bccb进行编码
为解决零频问题, 开始假设a,b,c个出现过一次
编码前概率区间为[0,1],此时abc的概率都是1/3,所以abc各占概率区间的1/3, 如b的概率区间为[0.33, 0,66]
开始编码......
第一个字符b,所以概率区间缩短为[0.33, 0,66]
此时a:b:c的比例为1:2:1,所以各个字符的概率区间变为a = [0.333,0.416], b = [0.416, 0.583], c = [0.583, 0.666]
第二个字符c,所以概率区间缩短为[0.583, 0.666]
此时a:b:c的比例为1:2:2,所以各个字符的概率区间变为a = [0.583,0.600], b = [0.600, 0.633], c = [0.633, 0.666]
第三个字符c,所以概率区间缩短为[0.633, 0.666]
此时a:b:c的比例为1:2:3,。。。。。。
最终概率区间缩小至[0.639, 0.650]
所以0.64就可以作为bccb的编码。

而解码的过程就是照着编码的过程重做一遍即可,
解码前概率区间为[0,1],此时abc的概率都是1/3,所以abc各占概率区间的1/3, 如b的概率区间为[0.33, 0,66]
所以0.64落在了b的概率区间内, 第一个字符为b
概率区间缩短为[0.33, 0,66], 此时a:b:c的比例为1:2:1,所以各个字符的概率区间变为a = [0.333,0.416], b = [0.416, 0.583], c = [0.583, 0.666]
所以0.64落在了c的概率区间内, 第二个字符为c
。。。。。。最终完成解码。

区间中的数需要的多少位来表示和区间长度的负对数成正比。而最终的区间长度是已编码符合概率值的乘积(显而易见)。
而log(AB)= log(A)+log(B), 所以最终的区间长度的对数就等于所有已编码符号单独概率值的对数的和。所以具有概率Pr[s]的符号s对输出编码的贡献是-logPr[s], 与符号信息量相同。
所以算术编码的输出位数接近最优。


2)字典方法,dictionary method
字典模式很好理解, 用字典里面的码字来替换原文,如果这个码字比原文的位数少,那么就实现了压缩, 如果你的字典是独有的, 不公开的, 那么就实现了加密。
那么为了实现压缩, 就要基于词或短语进行编码, 基于字符压缩效果肯定不好, 那么如果这个字典是静态的,因为各个领域的词和短语都不一样的, 所以不可能适用于所有文本。
也有半静态的,就是每次对要压缩的文本生成一个字典,这个方法肯定也不好。
所以就有自适应的字典方案(adaptive dictionary scheme), 这个就有技术含量了怎么产生自适应的字典了。
当然牛人是很多的,Ziv和Lempel发明了LZ77和LZ88两种方法。
牛人想出来的方法都是很简单,很好用的, 这个也不例外,基本原理就是文本的子串被指向其以前出现之处的指针所替换。
说白了,就是字典码书就是文本本身, 码字就是指针。个人感觉,在发明这个方法时, 作者可能并没有想到什么基于字典模式的方法,应该是后面的学者把它归到这类了。
我们就以LZ77来了解下这个方法,
LZ77的输出码是一系列三元组,(a,b,c), a表示往前回溯多远, b表示短语多长, c表示要输入的下一个字符。
为什么要有c项,是为没有出现过的字符准备的, 这个设计照顾了新字符引进的需要。
以abaabab为例,输出码为:
(0,0,a) (0,0,b) (2,1,a) (3,2,b)
这个方法需要在之前的文本中找到最大匹配窗口, 这个不能线性查找, 一般采用散列表, 或二分查找树来实现。

著名的Gzip就是这个算法的一个变体,
Gzip用hash table来定位之前出现的字符串, 用3个连续的字符作为hash键值,链表中记录了这三个字符在窗口中出现的位置信息。
出于效率的考虑,限制了链表的长度, 其实也没有必要记录过远的位置, 记较近的几个位置比较合理。
Gzip比较有意思的是,对指针的偏移值也做了哈夫曼编码,较常用的值用较少的编码。同时对字符串匹配长度值, 也采用哈夫曼编码。
当之前没有发现匹配的时候, 传递一个原始字符(raw character),有意思的是这个原始字符和字符串匹配长度值公用同一个编码。
也就是说第二项有可能是个字符串匹配长度值, 也有可能是个原始字符,反正前缀编码, 也不冲突, 用心良苦都是为了压缩。



转载于:https://www.cnblogs.com/fxjwind/archive/2011/07/04/2097718.html

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

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

相关文章

基于事件驱动架构构建微服务第8部分:在应用程序上实现事件溯源

原文链接:https://logcorner.com/building-microservices-through-event-driven-architecture-part8-implementing-eventsourcing-on-application/在本文中,我将讨论应用程序上的事件溯源实现。该层围绕领域并实现用例(特定于应用程序的业务规…

我们来聊点成年人的话题!

1 这个话题透漏着成年人都存在的问题,其中心思想行走在道德底线,让人不得不深思,句句入心2 哈哈哈哈哈哈哈哈哈哈哈哈哈画面惊人 图自动漫次元酱3 对不起,我不是你家的鸡,我是一只大鸟!!&#x…

yum安装最新的 LNMP

2019独角兽企业重金招聘Python工程师标准>>> 先添加几个源: rpm -Uvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-1.noarch.rpm rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm 1,安装nginx&a…

C#新版本风格项目文件(SDK风格项目 SDK-style project)

在VisualStudio中创建NetCore以上版本的项目,使用的都是新版本风格的项目文件。和旧版本.NetFramework版本的项目文件区别:双击项目可直接打开csproj文件进行编辑配置项目文件内容的改变项目属性文件夹图标更改项目引用去除,改成依赖项Nuget包…

史上最丧心病狂的商品定价套路:如何从数学角度,榨干你身上的每一分钱

全世界只有3.14 % 的人关注了爆炸吧知识世上没有精明的买家,只有精明的卖家。的确,卖家的嘴,骗人的鬼。在买与卖的博弈中,没有一个买家可以取胜。别不信,今天就让你见识下“卖家套路终极奥义”。按量定价,是…

东北大姐剪纸被误认为油画,遭人质疑二十多年,只因太过逼真,看完后:真香!不愧是天下第一剪!...

全世界只有3.14 % 的人关注了爆炸吧知识“这是剪纸?太惟妙惟肖了,我还以为是水彩画呢!”这是一位网友的留言。茂盛的树木、潺潺的流水……这些栩栩如生的场景,真难想象竟是出自,一双巧手和一把剪刀。这些作品,全部来自…

2021 年 9 月 TIOBE 指数 C# 同比增长突破 1.2%

TIOBE 编程社区指数是编程语言流行程度的指标。该指数每月更新一次。评级基于全球熟练工程师、课程和第三方供应商的数量。谷歌、必应、雅虎、维基百科、亚马逊、YouTube 和百度等流行搜索引擎用于计算评分。C# 近期发展状态不错,依旧在榜单中排第五,但排…

2010年5月系统集成项目管理工程师上午试卷参考答案(讨论版)

鉴于个人精力有限,其他答案将由51CTO相关工作人员不断更新,详见http://training.51cto.com/art/201005/200323.htm以题会友,欢迎跟贴拍砖、讨论。

那些35岁的程序员都去哪了

阅读本文大概需要11分钟。大家好,我是findyi,前段时间写过一篇关于大龄程序员的文章:那些40岁的程序员都去哪了,引发了大家的思考和讨论,不少读者私聊问:除了这些出路,还有没有其他可能&#xf…

Sharepoint学习笔记---如何在Sharepoint2010网站中整合Crystal Report水晶报表(显示数据 二)...

在Sharepoint学习笔记---如何在Sharepoint2010网站中整合Crystal Report水晶报表(显示数据一)中,解释了如何把Crystal Report整合到Sharepoint2010并把报表数据显示出来,但这样并不完整,因为我们在开发时是以系统帐户进…

那些拧不开瓶盖的女生全都是装的?理工男这样想......

全世界只有3.14 % 的人关注了爆炸吧知识昨天,超模君我正在思考人生,八岁的表妹突然提着一瓶矿泉水站在了我的面前。她可怜兮兮的说:“我想喝水,但是拧不开”。我:“........."超模君我明明亲眼见过她一口气拧开过…

【另类见解】秒杀并非高不可攀

“一提到秒杀很简单这个话题,我知道要被别人鄙视了:你不懂高并发... 这年头开头不画个思维导图都觉得掉价image谈到秒杀,网络上不少于几千片文章,但是大多大同小异。如果你的微信当中关注了几个编程技术类的公众号,我敢…

我又相信爱情了!

1 圣诞限定款的肥宅快乐水更好喝了吗?不!更贵了2 周边鬼才!这手机壳我爱了3 你以为是个王者,其实是个大脸......4 高温超导材料达到临界温度后能使物体悬浮在不同位置5 火山爆发你见过吗?6 我又相信爱情了!…

opencv计算两数组的乘积_#剑指Offer#12. 构建乘积数组

题目描述:给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1]。其中B中的元素B[i]A[0] * A[1]... * A[i-1] * A[i1]... * A[n-1]。不能使用除法。解题思路:首先,仔细理解题意,B[i]是A数组所有元素的乘积,但是没…

记一次 .NET 某桌面奇侠游戏 非托管内存泄漏分析

一:背景 1. 讲故事说实话,这篇dump我本来是不准备上一篇文章来解读的,但它有两点深深的感动了我。无数次的听说用 Unity 可做游戏开发,但百闻不如一见。游戏中有很多金庸武侠小说才有的名字,太赏心悦目了。000000df315…

成年人的数学公式

1 成年人的数学公式2 唯一对我说过“别走好吗”的人3 主人发起疯来有多可怕4 别人家的狗看到主人有危险▼你家的……▼5 蜘蛛捕食瞬间6 蜡烛重燃(冒的白烟是固态小颗粒的石蜡蒸汽,可燃)你点的每个赞,我都认真当成了喜欢

Linux运维实战之DNS的高级配置(转发器、视图等)

上次博文我们具体配置了一台DNS服务器并实现了主辅之间的区域传送,本次博文我们来看看DNS的一些高级配置。 在进行DNS的高级配置之前,必须要理解DNS的原理(参见http://sweetpotato.blog.51cto.com/533893/1596973) 并且对DNS的基础…

史上最烧脑的学习方法,看完瞬间涨姿势!

▲ 点击查看 在美国,有一个天才儿童计划,选拔一批“天才”儿童进入天才班。这个计划是为了保证每个人接受平等教育机会的同时,也为精英成长提供合适的土壤。美国所谓的天才和精英是怎样的标准呢?进入天才班的儿童首先要通过一个叫…

WPF轮播图实现方式(二)

WPF开发者QQ群: 340500857 | 微信群 -> 进入公众号主页 加入组织欢迎转发、分享、点赞、在看,谢谢~。 01—效果预览02—代码如下一、EmphasizerCarousel.cs 代码如下using System; using System.Collections.Generic; using System.Collections.Obj…

实现链栈的各种基本运算的算法_LeetCode基础算法题第78篇:如何不用加减号实现两数的加法运算?...

一直很纠结算法的文章应该怎么写。最后觉得还是从最简单的level开始写吧,一开始就弄些重量级的,什么人工智能,机器学习的算法,还要有大量的数学以及优化的知识,小白们估计会很郁闷,当然我也不一定能做出来对…