We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前端在性能优化那块有提到过gzip,但是gzip 的实现原理只是简单提了一下是基于deflate的算法,使用的是LZ77 + huffman Code。今天就来详细的总结下原理,不过有些问题还是没搞清楚,什么问题后面再说。 在这之前有个问题要先说下,nginx 和 webpack 中都是能做 gzip 压缩的,那有什么区别呢? web 服务器(nginx)在向客户端发送gzip文件的时候,会先在本地文件系统查找 .gz 的文件,如果没有,则会去生成一份。生成的时候肯定会占用cpu的资源,所以当请求量比较大的时候,会占用较多的cpu来生成gz文件。而 webpack 的 gzip 则是在编译阶段就生成,所以服务器不用再生成,可以达到减少cpu资源占用的目的。
LZ77 这个算法是两个以色列的大神 Lempel 和 Ziv 于1977 年提出的,所以简称为LZ77。
压缩原理其实很简单,就是找出那些重复出现的字符串,然后用更短的符号代替, 从而达到缩短字符串的目的。比如 某个js文件出现了大量的 let 关键字,我们就可以用�前面 let 的坐标值代替。事实上, 只要保证对应关系,可以用任意字符代替那些重复出现的字符串。
let
如果一个文件的重复率越高,那么压缩率就越高;相反,如果一个文件毫无重复,那么就无法被压缩。
LZ77 压缩算法采用字典的方式进行压缩,把数据中一些可以组织成短语(最长字符)的字符加入字典,然后再有相同字符出现采用标记来代替字典中的短语,如此通过标记代替多数重复出现的方式以进行压缩。
LZ77的主要算法逻辑就是,先通过前向缓冲区预读数据,然后再向滑动窗口移入(滑动窗口有一定的长度),不断的寻找能与字典中短语匹配的最长短语,然后通过标记符标记。我们还以字符ABD为例子,看如下图:
目前从前向缓冲区中可以和滑动窗口中可以匹配的最长短语就是(A,B),然后向前移动的时候再次遇到(A,B)的时候采用标记符代替。
当压缩数据的时候,前向缓冲区与移动窗口之间在做短语匹配的是后会存在2种情况:
一旦把n个符号编码并生成响应的标记,就将这n个符号从滑动窗口的一端移出,并用前向缓冲区中同样数量的符号来代替它们,如此,滑动窗口中始终有最新的短语。
我们采用图例来看:
1、开始
2、滑动窗口中没有数据,所以没有匹配到短语,将字符A标记为A
3、滑动窗口中有A,没有从缓冲区中字符(BABC)中匹配到短语,依然把B标记为B
4、缓冲区字符(ABCB)在滑动窗口的位移6位置找到AB,成功匹配到短语AB,将AB编码为(6,2,C)
5、缓冲区字符(BABA)在滑动窗口位移4的位置匹配到短语BAB,将BAB编码为(4,3,A)
6、缓冲区字符(BCAD)在滑动窗口位移2的位置匹配到短语BC,将BC编码为(2,2,A)
7、缓冲区字符D,在滑动窗口中没有找到匹配短语,标记为D
8、缓冲区中没有数据进入了,结束
解压类似于压缩的逆向过程,通过解码标记和保持滑动窗口中的符号来更新解压数据。
当解码字符标记:将标记编码成字符拷贝到滑动窗口中
解码短语标记:在滑动窗口中查找响应偏移量,同时找到指定长短的短语进行替换。
我们还是采用图例来看下:
2、符号标记A解码
3、符号标记B解码
4、短语标记(6,2,C)解码
5、短语标记(4,3,A)解码
6、短语标记(2,2,A)解码
7、符号标记D解码
大多数情况下LZ77压缩算法的压缩比相当高,当然了也和你选择滑动窗口大小,以及前向缓冲区大小,以及数据熵有关系。其压缩过程是比较耗时的,因为要花费很多时间寻找滑动窗口中的短语匹配,不过解压过程会很快,因为每个标记都明确告知在哪个位置可以读取了。
哈夫曼设计了一个贪心算法来构造最优前缀码,被称为哈夫曼编码(Huffman code), 其正确性证明依赖于贪心选择性质和最优子结构。哈夫曼编码可以很有效的压缩数据,具体压缩率依赖于数据本身的特性
变长编码可以达到比定长编码好得多的压缩率,其思想是赋予高频字符(出现频率高的字符)短(码字长度较短)码字,赋予低频字符长码字。例如,我们 用 ASCII 字符编辑一个文本文档,不论字符在整个文档中出现的频率,每个字符都要占 用一个字节。如果我们使用变长编码的方式,每个字符因在整个文档中的出现频率不同导致码字长度不同,有的可能占用一个字节,而有的可能只占用一比特,这个时候,整 文档占用空间就会比较小了。当然,如果这个文本文档相当大,导致每个字符的出现频率基本相同,那么此时所谓变长编码在压缩方面的优势就基本不存在了(这点要十分明确,这是为什么压缩要分块的原因之一)
哈夫曼编码会自底向上构造出一棵对应最优编码的二叉树,我们使用下面这个例子来说明哈夫曼树的构造过程
首先,我们已知在某个文本中有如下字符及其出现频率:
构造过程如下图所示:
利用库中的优先级队列实现哈夫曼树,最后基于哈夫曼树最终实现文件压缩。
参考: 数据流压缩原理(Deflate压缩算法、gzip、zlib) 图解LZ77压缩算法 图片压缩知识梳理(1) - PNG 原理 PNG图片压缩原理--屌丝的眼泪 常用图片的构造及其压缩原理
The text was updated successfully, but these errors were encountered:
Yuanfang-fe
No branches or pull requests
前端在性能优化那块有提到过gzip,但是gzip 的实现原理只是简单提了一下是基于deflate的算法,使用的是LZ77 + huffman Code。今天就来详细的总结下原理,不过有些问题还是没搞清楚,什么问题后面再说。
在这之前有个问题要先说下,nginx 和 webpack 中都是能做 gzip 压缩的,那有什么区别呢?
web 服务器(nginx)在向客户端发送gzip文件的时候,会先在本地文件系统查找 .gz 的文件,如果没有,则会去生成一份。生成的时候肯定会占用cpu的资源,所以当请求量比较大的时候,会占用较多的cpu来生成gz文件。而 webpack 的 gzip 则是在编译阶段就生成,所以服务器不用再生成,可以达到减少cpu资源占用的目的。
LZ77
LZ77 这个算法是两个以色列的大神 Lempel 和 Ziv 于1977 年提出的,所以简称为LZ77。
LZ77原理:
压缩原理其实很简单,就是找出那些重复出现的字符串,然后用更短的符号代替, 从而达到缩短字符串的目的。比如 某个js文件出现了大量的
let
关键字,我们就可以用�前面 let 的坐标值代替。事实上, 只要保证对应关系,可以用任意字符代替那些重复出现的字符串。如果一个文件的重复率越高,那么压缩率就越高;相反,如果一个文件毫无重复,那么就无法被压缩。
LZ77 压缩算法采用字典的方式进行压缩,把数据中一些可以组织成短语(最长字符)的字符加入字典,然后再有相同字符出现采用标记来代替字典中的短语,如此通过标记代替多数重复出现的方式以进行压缩。
关键词术语:
LZ77的主要算法逻辑就是,先通过前向缓冲区预读数据,然后再向滑动窗口移入(滑动窗口有一定的长度),不断的寻找能与字典中短语匹配的最长短语,然后通过标记符标记。我们还以字符ABD为例子,看如下图:
目前从前向缓冲区中可以和滑动窗口中可以匹配的最长短语就是(A,B),然后向前移动的时候再次遇到(A,B)的时候采用标记符代替。
压缩
当压缩数据的时候,前向缓冲区与移动窗口之间在做短语匹配的是后会存在2种情况:
一旦把n个符号编码并生成响应的标记,就将这n个符号从滑动窗口的一端移出,并用前向缓冲区中同样数量的符号来代替它们,如此,滑动窗口中始终有最新的短语。
我们采用图例来看:
1、开始
2、滑动窗口中没有数据,所以没有匹配到短语,将字符A标记为A
3、滑动窗口中有A,没有从缓冲区中字符(BABC)中匹配到短语,依然把B标记为B
4、缓冲区字符(ABCB)在滑动窗口的位移6位置找到AB,成功匹配到短语AB,将AB编码为(6,2,C)
5、缓冲区字符(BABA)在滑动窗口位移4的位置匹配到短语BAB,将BAB编码为(4,3,A)
6、缓冲区字符(BCAD)在滑动窗口位移2的位置匹配到短语BC,将BC编码为(2,2,A)
7、缓冲区字符D,在滑动窗口中没有找到匹配短语,标记为D
8、缓冲区中没有数据进入了,结束
解压
解压类似于压缩的逆向过程,通过解码标记和保持滑动窗口中的符号来更新解压数据。
当解码字符标记:将标记编码成字符拷贝到滑动窗口中
解码短语标记:在滑动窗口中查找响应偏移量,同时找到指定长短的短语进行替换。
我们还是采用图例来看下:
1、开始
2、符号标记A解码
3、符号标记B解码
4、短语标记(6,2,C)解码
5、短语标记(4,3,A)解码
6、短语标记(2,2,A)解码
7、符号标记D解码
优缺点
大多数情况下LZ77压缩算法的压缩比相当高,当然了也和你选择滑动窗口大小,以及前向缓冲区大小,以及数据熵有关系。其压缩过程是比较耗时的,因为要花费很多时间寻找滑动窗口中的短语匹配,不过解压过程会很快,因为每个标记都明确告知在哪个位置可以读取了。
Huffman
哈夫曼设计了一个贪心算法来构造最优前缀码,被称为哈夫曼编码(Huffman code), 其正确性证明依赖于贪心选择性质和最优子结构。哈夫曼编码可以很有效的压缩数据,具体压缩率依赖于数据本身的特性
这里我们先介绍几个概念:
变长编码可以达到比定长编码好得多的压缩率,其思想是赋予高频字符(出现频率高的字符)短(码字长度较短)码字,赋予低频字符长码字。例如,我们 用 ASCII 字符编辑一个文本文档,不论字符在整个文档中出现的频率,每个字符都要占 用一个字节。如果我们使用变长编码的方式,每个字符因在整个文档中的出现频率不同导致码字长度不同,有的可能占用一个字节,而有的可能只占用一比特,这个时候,整 文档占用空间就会比较小了。当然,如果这个文本文档相当大,导致每个字符的出现频率基本相同,那么此时所谓变长编码在压缩方面的优势就基本不存在了(这点要十分明确,这是为什么压缩要分块的原因之一)
构造过程
哈夫曼编码会自底向上构造出一棵对应最优编码的二叉树,我们使用下面这个例子来说明哈夫曼树的构造过程
首先,我们已知在某个文本中有如下字符及其出现频率:
构造过程如下图所示:
利用库中的优先级队列实现哈夫曼树,最后基于哈夫曼树最终实现文件压缩。
未搞清楚的问题,希望有知道的小伙伴帮我解惑:
如果字典集是整个文件的字典集(随滑动窗口递增),那搜索效率会不会变的很慢?如果文件很大,字典集会不会很占用内存资源?如果不是全部字典集,感觉很难做到平均70%的压缩率。(猜测应该是递增)
参考:
数据流压缩原理(Deflate压缩算法、gzip、zlib)
图解LZ77压缩算法
图片压缩知识梳理(1) - PNG 原理
PNG图片压缩原理--屌丝的眼泪
常用图片的构造及其压缩原理
The text was updated successfully, but these errors were encountered: