//滑动窗口的固定大小 4096字节
#define PGLZ_HISTORY_SIZE 4096
3.2 LZ编码过程
LZ压缩算法使用一个三元组<o, l, c>来对字符串序列进行编码。其中o是offset(偏移量)的缩写,l是length(长度)的缩写,而c则是代表先行缓冲区中位于匹配项之后的字符(character)。也有的文献资料称之为码字(Code Word)。
现在来详细说明一个三元组<o, l, c>中这几个数字对应的实际含义。这里待编码的字符串序列是“HELLOWORLD”。假定LZ窗口大小是5字节,其中查找缓冲区是3字节,而先行缓冲区为2字节。由于窗口大小是固定的,所以同一时刻(当然,一开始时候,查找缓冲区没有字符),查找缓冲区中最多有3个字节数据,先行缓冲区最多容纳2字节数据。
假如现在已经对字符‘H’、'E'、'L'、'L'、'O'、'W'这6字符编码完成,其中'L'、'O'、'W'字符位于查找缓冲区中,而先行缓冲区中的字符是'O'、'R'。如下图所示:
编码器将会通过“查找指针”在查找缓冲区中不断移动(移动方向如上图黑色箭头所示),来判断是否有字符和先行缓冲区中的(第一个)待编码字符相同。这里先行缓冲区中的待编码字符是‘O’。通过判断可知,在查找缓冲区中的第2个位置处有一个字符‘O’和先行缓冲区中的第一个符号相同,该(查找)指针与先行缓冲区的距离称为“偏移量(offset)”,这里偏移量是2。
此时,LZ编码器会继续查看并判断查找缓冲区中该“查找指针”位置之后的字符,是否与先行缓冲区中第一个字符之后的字符连续相匹配。在查找缓冲区中与先行缓冲区中连续相匹配的字符的数量,我们称之为“匹配长度”。从上图可以看到位于查找缓冲区中的查找指针后面的一个字符是‘W’,而先行缓冲区中第一个待编码字符之后的字符是‘R’,不相匹配。所以这里的匹配长度length等于1。
先行缓冲区中匹配字符之后的第一个字符是‘R’,所以可以得到一个三元组:<2, 1, C(R)>。待字符‘O’编码好之后,滑动窗口移动一个字符(字节)。此时的查找缓冲区与先行缓冲区中的内容如下图所示:
LZ编码器继续对先行缓冲区中的字符‘R’进行编码,重复上面的逻辑判断过程。首先在查找缓冲区(Search Buffer)中通过移动查找指针,判断是否有字符和先行缓冲区中的第一个字符(待编码)相等,若有,则继续判断是否有连续的字符和先行缓冲区的字符相匹配,通过上图可以看到,查找缓冲区中没有与字符‘R’相等的符号。所以偏移量为0,其长度也为0,字符编码是‘R’。所以得出其三元组为:<0, 0, C(L)>。得到如下图所示的编码。
最后,还剩下字符‘D’未编码,通过前面的步骤可知,查找缓冲区中没有与之匹配的字符,所以该三元组是<0, 0, C(D)>。最终完成对序列字符“HELLOWORLD”的编码操作,如下图所示:
对于LZ编码,其整个压缩过程可以划分为以下三个步骤:
(1) 用搜索缓冲区中可用的模式查找从当前位置开始的字符串的最长匹配。
(2) 输出一个三元组<o, l, c>
;
o
:偏移量,表示为了找到匹配字符串的开始,我们需要向后移动的位置数。
l
:表示匹配的长度。
c
:字符,表示匹配后找到的字符。
(3) 向右移动查找指针 + 1。
3.3 LZ编码过程中的三种可能性
通过上面对LZ编码过程的描述,可以看出,编码器使用LZ算法对一个符号序列进行压缩时候,可能会遇到以下几种情形。
(1) 查找缓冲区里存在与先行缓冲区中待编码的字符(即存在匹配项)。
(2) 查找缓冲区里没有与先行缓冲区中待编码字符匹配的字符。
(3) 查找缓冲区中有匹配字符串,且该字符串在先行缓冲区字符串中延伸。
前面(1)和(2)两种情形好理解,即找到与未找到问题。对于第(3)项的理解,需要记住这样一个事实。即对于LZ算法,仅要求匹配项的字符位置起点(即查找与先行缓冲区中的待编码字符)位于查找缓冲区中,但是若匹配到先行缓冲区中的多个字符,则其终点可以延续到先行缓冲区中。借助这段话,再来理解情形(3),就相对容易许多。
3.4 LZ解码过程
由于LZ算法是无损压缩算法,这意味着我们能够完全恢复原始的数据,因此,我们不能从随机的LZ三元组开始解压缩。相反,我们必须得从初始的三元组开始解压缩,因为LZ编码的三元组是基于搜索缓冲区的。
假设我们已经完成对字符‘H’、‘E’、‘L’、‘L’、‘O’、‘W’的编码,如下图所示。
注意,编码与解码过程中 其窗口(查找缓冲区,先行缓冲区)大小是固定的,否则,其解压缩过程将会以失败而告终。
现在依次对上面的三元组:<2, 1, C(R)>、<0, 0, C(L)>和<0, 0, C(D)>进行解码。
(1) 解码<2, 1, C(R)>
由于其偏移量(offset)等于2,所以我们将查找指针(向左)移动两位;而字符匹配的长度(length)是1,所以我们将查找指针所指向的字符复制一个。其解码过程如下图所示:
该三元组解析完成之后,得到的窗口图如下:
(2) 解码<0, 0, C(L)>
由于偏移量(offset)等于0,且匹配字符长度为0,则表明在查找缓冲区中没有与之匹配的内容,且下一个字符是‘L’。所以则在已解码的字符串后面增加一个字符‘L’,并将窗口移动一个字符。如下图所示:
(3) 解码<0, 0, C(D)>
和解码<0, 0, C(L)>一样,由于其偏移量和匹配长度都为0,所以其下一个字符是‘D’。则最终解码(压缩)得到的完整字符串是:HELLOWORLD。如下图所示:
3.5 LZ算法实现
在github上有一份 LZ算法 的源码实现。该算法中使用了二叉树来作为编码过程中的偏移量和长度等索引,以加快编码、解码的速度。针对这个LZ算法的源码,后期将专门写一篇文章来进行分析、学习。
4. 数据压缩优缺点
没有任何一件事物是完美的,数据压缩亦是如此。既然有优点,肯定也有它的缺点所在。下面分别对数据压缩的优缺点进行一个简单的概述。
4.1 优点
(1) 同一个数据文件,需要更少的磁盘空间。这意味着可以存储更多的数据文件;
(2) 文件传输、读写速度更快。
4.2 缺点
(1) 增加了CPU的负载,对于一些较为复杂的压缩算法,尤其如此。
(2) 增加了复杂性;
(3) 提高了传输误差影响。
原文链接:https://jishuin.proginn.com/p/763bfbd6312f
LZ77压缩算法原理的理解
数据压缩是一个减小数据存储空间的过程,目前被应用在软件工程的各个地方,了解其一些原理,方便我们更好的甄选压缩方案。
压缩方案有很多种,常见的就是有损和无损压缩。霍夫曼编码和LZ77(Lempel-Ziv-1977)都是无损压缩,其中霍夫曼是采用最小冗余编码的算法进行压缩,而LZ77是采用字典的方式进行压缩。关于霍夫曼编码的算法,网上有很多对其详细的讲解,我们本篇幅不在细说,主要图解一下LZ77压缩算法的方式,看看其有哪些优缺点。
数据为何是可以压缩的,因为数据都会表现出一定的特性,称为熵。绝大多数的数据所表现出来的容量往往大于其熵所建议的最佳容量。比如所有
Ziv和Lempel于1977年发表题为“顺序数据压缩的一个通用算法(A Universal Algorithm for Sequential Data Compression )”的论文,论文中描述的算法被后人称为LZ77算法。值得说的是,LZ77严格意义上来说不是一种算法,而是一种编码理论。同Huffman编码一样,只定义了原理,并没有定义如何实现。基于这种理论来实现的算法才称为LZ77算法,或者人们更愿意称为LZ77变种。实际上这类算法已经有很多了,比如LZSS、LZB、LZH等。
字典编码本质上是将在字典中出现过的字符串使用一个索引值代替,以此来达到压缩目的。基于字典的压缩算法有很多,LZ77和LZ78是最原始的两个算法,后者是前者的变体,原理基本上相似。本文对LZ77字典编码的压缩和解压缩流程进行介绍。...
LZ77简介
Ziv和Lempel于1977年发表题为“顺序数据压缩的一个通用算法(A Universal Algorithm for Sequential Data Compression )”的论文,论文中描述的算法被后人称为LZ77算法。值得说的是,LZ77严格意义上来说不是一种算法,而是一种编码理论。同Huffman编码一样,只定义了原理,并没有定义如何实现。基于这种理论来实现的算法才称为LZ77算法,或者人们更愿意称为LZ77变种。实际上这类算法已经有很多了,比如LZSS、LZB、LZH等。至今
一、算法介绍LZ77算法是采用自适应的字典模型,也就i是将已经编码的信息作为字典,如果要编码的字符曾经出现过,就输出该字符串的出现位置以及长度,否则输出新的字符串。二、算法思想它的核心思想是在前面已经出现过的数据中找重复出现的字符,根据局部性原理,入股一个字符串要重复,那么也实在附近重复,远的地方就不要找了,因此设置一个滑动窗口,每次都在这个窗口里面找重复出现的字符。关于这个滑动窗口的大小,理论上是
LZ77算法是无损压缩算法,由以色列人Abraham Lempel发表于1977年。LZ77是典型的基于字典的压缩算法,现在很多压缩技术都是基于LZ77。鉴于其在数据压缩领域的地位,本文将结合图片和源码详细介绍其原理。2.
LZ77算法是一种无损数据压缩算法,由Abraham Lempel和Jacob Ziv于1977年提出。它是一种字典编码方法,通过查找数据中重复出现的字符串,并用较短的标记来替代这些字符串,从而实现压缩。
LZ77压缩原理
初始LZ77
LZ77是基于字节的通用压缩算法,它的原理就是将源文件中的重复字节(即在前文中出现的重复字节)使用(offset,length,nextchar)的三元组进行替换
长度–offset,距离—length,先行缓冲匹配串的下一个字符
总共三个字节
初始LZ77的缺陷
只是距离按照一个字节的长度,那么只能在先行缓冲区找256个以内的字符,所以压缩率不是很高
改进...
LZ77是一种基于字典的算法,它将长字符串(也称为短语)编码成短小的标记,用小标记代替字典中的短语,从而达到压缩的目的。
LZ77使用的是一个前向缓冲区和一个滑动窗口来维护字典。它首先将一部分数据载入前向缓冲区,一旦数据
中的短语通过前向缓冲区,那么它将移动到滑动窗口中,并变成字典的一部分,随着滑动窗口移动,字典中的内
容也在不断的更新,也就是说它是变更新字典,边进行压缩。...