即使累死自己,也要饿死同行——网页压缩算法值得你收藏!

作者 | 谭军一

虽然过去不能改变,“未来” 可以 !

网页数据或者图像数据往往比较大,对于传输和存储都不太友好,我们在请求静态资源时能看到 Request Headers的accept-encoding 通常会包含 gzip, deflate, br 三种格式,其中 deflate 也是 PNG 图片的核心压缩算法,它主要是由 LZ77 算法与哈夫曼编码(Huffman Coding)组成的一个无损数据压缩算法,下面分别介绍它们的基础原理与 JS 部分算法实现。

1. LZ77 算法

1.1 算法简介

LZ77 算法是由 Lempel-Ziv 在 1977 发明的,其核心思想是比对相邻区域内的数据,获取数据中尽可能多的连续重复数据。然后使用坐标加长度的方式进行替换。LZ77 本身是较为简单却非常高效的压缩算法,为了获得更大的压缩比例,它与 Base64 进行配合使用。我们在学习 LZ77 时必须了解三个关键词:

滑动窗口: 指固定长度范围(窗口大小)的地址区间,窗口内存放输入流前的多个数据,每次循环窗口向右移动。

缓冲区: 预先读取一定长度的数据内容到缓冲区,用作与窗口数据进行对比。每次循环时与滑动窗口一起向右移动

字典: 滑动窗口内的字符可以组成多个字符串,这些字符串的组合称为字典。在滑动窗口跟随指针滑动过程中,字典跟随滑动窗口不断的改变。当缓冲区内的字符串能与窗口的字符串相匹配时则进行标记,被标记的字符串通过起始坐标,距离及下一个字符替换,所以通常我们将长度大于 3 个匹配的字符串才放入字典。例如 ABCD 中包含 ABC,BCD,ABCD 这三个。

1.2 LZ77 压缩

1.2.1 压缩原理

假如现在有一串字符 ABABCBABABCAD,设置缓冲区大小为 4,滑动窗口大小为 8 个字节。在初始时前四个字符 ABAB 进入缓冲区,滑动窗口为空,此时记录下一个字符 A

当窗口向右移动两个字符时,窗口内的AB和缓冲区的 AB 匹配,则进行标记替换,其中 6 表示 AB 在滑动窗口中的位置,2 表示匹配到的字符长度,C 为下一个字符。此时指针增加匹配长度 2

继续移动一个字符,发现匹配到 BAB,则继续添加匹配标识:

以此类推,直到匹配结束:

1.2.2 数据预处理

我们通常存储或者传输过程中为 16 进制数据或者字符,在编码时需要转换成对应的 ASICII码:

const str = 'ababcbababcadababcbababcadababcbababcadababcbababcadababcbababcadababcbababcadababcbababcadababcbababcadababcbababcadababcbababcadababcbababcadababcbababcad'
const arr = str.split('').map(char => char.charCodeAt())

 得到结果:
[ 97,  98,  97,  98,  99,  98,  97, 98, 97, 98, 99, 97, 100,  97,  98,  97,  98,  99,  98, 97, 98, 97, 98, 99 ...]
1.2.3 滑动窗口压缩

压缩的比例,压缩的速度与滑动窗口和缓冲区的大小密切相关,通常被压缩的文件比较大,所以需要进行分片压缩,通常单片的大小为 64K,片与片之间不会进行窗口比较。扫描字符串开始编码, 移动编码原理见 1.1.2

	var X = 1<<15 /* 距离用15位二进制表示*/
	for(var i=0;i<str.length;i++)
	{
		var max_len=0, max_off=0;// 最长匹配和位置
		if( i< str.length-3) {
			var d1 = String.fromCharCode(str[i],str[i+1],str[i+2]); //三字节字符串加入索引
			if(dic[d1]) {
				dic[d1].push(i);
			}else{
				dic[d1] = [i];
			}
			for(var k=dic[d1].length-2; k>=0; k--) {
				var j = dic[d1][k];
				if(j <= i - X) {
					break;
				}
				var len = strcmp(str, i, j); //在索引位置处查找最长匹配
				if(len > max_len) {
					max_len = len;
					max_off = i - j;
				}
			}
		}
		...
	}

实现 在字符串 str 中 比较 a,b 位置处的最长匹配:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值