LZ77压缩算法编码原理详解(结合图片和简单代码)

转载自:https://www.cnblogs.com/junyuhuang/p/4138376.html

前言

  LZ77算法是无损压缩算法,由以色列人Abraham Lempel发表于1977年。LZ77是典型的基于字典的压缩算法,现在很多压缩技术都是基于LZ77。鉴于其在数据压缩领域的地位,本文将结合图片和源码详细介绍其原理。

原理介绍:

  首先介绍几个专业术语。

  1.lookahead buffer(不知道怎么用中文表述,暂时称为待编码区):

  等待编码的区域

  2. search buffer:

  已经编码的区域,搜索缓冲区

  3.滑动窗口:

  指定大小的窗,包含“搜索缓冲区”(左) + “待编码区”(右)

  

  接下来,介绍具体的编码过程:

  为了编码待编码区, 编码器在滑动窗口的搜索缓冲区查找直到找到匹配的字符串。匹配字符串的开始字符串与待编码缓冲区的距离称为“偏移值”,匹配字符串的长度称为“匹配长度”。编码器在编码时,会一直在搜索区中搜索,直到找到最大匹配字符串,并输出(o, l ),其中o是偏移值, l是匹配长度。然后窗口滑动l,继续开始编码。如果没有找到匹配字符串,则输出(0, 0, c),c为待编码区下一个等待编码的字符,窗口滑动“1”。算法实现将类似下面的:

  

while( lookAheadBuffer not empty )
{get a pointer (position, match) to the longest match in the window for the lookAheadBuffer;output a (position, length, char()) triple;shift the window length+1 characters along;
}

  主要步骤为:

  1.设置编码位置为输入流的开始

  2.在滑窗的待编码区查找搜索区中的最大匹配字符串

  3.如果找到字符串,输出(偏移值, 匹配长度), 窗口向前滑动“匹配长度”

  4.如果没有找到,输出(0, 0, 待编码区的第一个字符),窗口向前滑动一个单位

  5.如果待编码区不为空,回到步骤2

实例:

  现在有字符串“AABCBBABC”,现在对其进行编码。

  一开始,窗口滑入如图位置

  

  由图可见,待编码缓冲区有“AAB”三个字符,此时搜索缓冲区还是空的。所以编码第一个字符,由于搜索区为空,故找不到匹配串,输出(0,0, A),窗口右移一个单位,如下图

  

  此时待编码区有“ABC”。开始编码。最先编码"A",在搜索区找到"A"。由于没有超过待编码区,故开始编码"AB",但在搜索区没有找到匹配字符串,故无法编码。因此只能编码"A"。

输出(1, 1)。即为相对于待编码区,偏移一个单位,匹配长度为1。窗口右滑动匹配长度,即移动1个单位。如下图

  

  一样,没找到,输出(0, 0, B),右移1个单号,如下图

  

  输出(0, 0, C),右移1个单位,如下图

  

  输出(2, 1),右移1个单位,如下图

  

  输出(3, 1), 右移1个单位,如下图

  

  开始编码"A",在搜索缓冲区查找到匹配字符串。由于待编码缓冲区没有超过,继续编码。开始编码"AB",也搜索到。不要停止,继续编码“ABC”,找到匹配字符串。由于继续编码,则超过了窗口,故只编码“ABC”,输出(5, 3),偏移5,长度3。右移3个单位,如下图

  

  此时待编码缓冲区为空,停止编码。

  最终输出结果如下

  

python代码实现: 

class Lz77:def __init__(self, inputStr):self.inputStr = inputStr #输入流self.searchSize = 5    #搜索缓冲区(已编码区)大小self.aheadSize = 3     #lookAhead缓冲区(待编码区)大小 self.windSpiltIndex = 0 #lookHead缓冲区开始的索引self.move = 0self.notFind = -1   #没有找到匹配字符串#得到滑动窗口的末端索引def getWinEndIndex(self):return self.windSpiltIndex + self.aheadSize#得到滑动窗口的始端索引def getWinStartIndex(self):return self.windSpiltIndex - self.searchSize#判断lookHead缓冲区是否为空def isLookHeadEmpty(self):return True if self.windSpiltIndex + self.move> len(self.inputStr) - 1   else Falsedef encoding(self):step = 0print("Step   Position   Match   Output")while not self.isLookHeadEmpty():#1.滑动窗口self.winMove()#2. 得到最大匹配串的偏移值和长度(offset, matchLen) = self.findMaxMatch()#3.设置窗口下一步需要滑动的距离self.setMoveSteps(matchLen) if matchLen == 0:#匹配为0,说明无字符串匹配,输出下一个需要编码的字母nextChar = self.inputStr[self.windSpiltIndex]result = (step, self.windSpiltIndex, '-',  '(0,0)' + nextChar)else:result = (step, self.windSpiltIndex, self.inputStr[self.windSpiltIndex - offset: self.windSpiltIndex - offset + matchLen], '(' + str(offset) + ',' + str(matchLen) + ')')#4.输出结果self.output(result)    step = step + 1        #仅用来设置第几步#滑动窗口(移动分界点)def winMove(self):self.windSpiltIndex = self.windSpiltIndex + self.move#寻找最大匹配字符并返回相对于窗口分界点的偏移值和匹配长度def findMaxMatch(self):matchLen = 0offset = 0minEdge = self.minEdge() + 1  #得到编码区域的右边界#遍历待编码区,寻找最大匹配串for i in range(self.windSpiltIndex + 1, minEdge):#print("i: %d" %i)offsetTemp = self.searchBufferOffest(i)if offsetTemp == self.notFind: return (offset, matchLen)offset = offsetTemp #偏移值matchLen = matchLen + 1  #每找到一个匹配串,加1return (offset, matchLen)#入参字符串是否存在于搜索缓冲区,如果存在,返回匹配字符串的起始索引def searchBufferOffest(self, i):searchStart = self.getWinStartIndex()searchEnd = self.windSpiltIndex #下面几个if是处理开始时的特殊情况if searchEnd < 1:return self.notFindif searchStart < 0:searchStart = 0if searchEnd == 0:searchEnd = 1searchStr = self.inputStr[searchStart : searchEnd]  #搜索区字符串findIndex = searchStr.find(self.inputStr[self.windSpiltIndex : i])if findIndex == -1:return -1return len(searchStr) - findIndex#设置下一次窗口需要滑动的步数def setMoveSteps(self, matchLen):if matchLen == 0:self.move = 1else:self.move = matchLendef minEdge(self):return len(self.inputStr)  if len(self.inputStr) - 1 < self.getWinEndIndex() else self.getWinEndIndex() + 1def output(self, touple):print("%d      %d           %s     %s" % touple)if __name__ == "__main__":lz77 = Lz77("AABCBBABC")lz77.encoding()

  只是简单的写了下,没有过多考虑细节,请注意,这不是最终的代码,只是用来阐述原理,仅供参考。输出结果就是上面的输出(格式由于坑爹的博客园固定样式,代码位置有偏移,请注意)

解压缩:

Decompression Process Example

The input stream for this example is the output of the compression example above.

The following table shows the construction of the output stream as it is built from the sequence of pointers in the input stream. The table includes the following columns:

Step: Indicates the number of the decoding step. A step in the table finishes every time the decoding algorithm appends the set of bytes identified by the pointer to the output stream.

Input Pointer: The next pointer from the input stream.

Append Bytes: The bytes that the pointer identifies to be appended to the output stream.

Output Stream: The output stream as it looks at the end of each step.

Step

Input Pointer

Append Bytes

Output Stream

1.

(0,0)A

A

A

2.

(1,1)

A

A A

3.

(0,0)B

B

A A B

4.

(0,0)C

C

A A B C

5.

(2,1)

B

A A B C B

6.

(1,1)

B

A A B C B B

7.

(5,3)

ABC

A A B C B B A B C

参考文章:

  http://msdn.microsoft.com/en-us/library/ee916854.aspx

  http://en.wikipedia.org/wiki/LZ77_and_LZ78

  http://cs.stanford.edu/people/eroberts/courses/soco/projects/2000-01/data-compression/lossless/lz77/algorithm.htm

  以上几篇文章都是很好的讲解LZ77原理的,大家有兴趣的可以参考下。由于国内介绍该算法的比较少,故这些英文文章帮助还是挺大的。

LZ77 压缩和解压缩相关推荐

  1. 详解LZ77字典编码压缩和解压缩流程(典型的压缩算法)

    字典编码本质上是将在字典中出现过的字符串使用一个索引值代替,以此来达到压缩目的.基于字典的压缩算法有很多,LZ77和LZ78是最原始的两个算法,后者是前者的变体,原理基本上相似.本文对LZ77字典编码 ...

  2. LZ77算法压缩和解压缩

    LZ77简介 Ziv和Lempel于1977年发表题为"顺序数据压缩的一个通用算法(A Universal Algorithm for Sequential Data Compression ...

  3. asp在线压缩和解压缩文件(文件夹)

    asp在线压缩和解压缩文件(文件夹) <% '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ '\\ '\\ 1. c:\ ...

  4. java 解压与压缩代码_Java实现多文件压缩和解压缩代码详解

    Java实现多文件压缩和解压缩代码 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStre ...

  5. Java 的zip压缩和解压缩

    Java 的zip压缩和解压缩 好久没有来这写东西了,今天中秋节,有个东西想拿出来分享,一来是工作中遇到的问题,一来是和csdn问候一下,下面就分享一个Java中的zip压缩技术,代码实现比较简单,代 ...

  6. Linux之压缩和解压缩命令

    Linux之压缩和解压缩命令 1. 压缩格式的介绍 Linux默认支持的压缩格式: .gz .bz2 .zip 说明: .gz和.bz2的压缩包需要使用tar命令来压缩和解压缩 .zip的压缩包需要使 ...

  7. asp.net在线压缩和解压缩的实现

    我们经常会遇到批量上传的问题,也会遇到将某个目录下所有文件都上传到服务器上的问题.那么,如何解决此类问题呢?以前的技术一般采用ActiveX等方式,这里我采用SharpZlib来实现,听说VS2005 ...

  8. linux下文件的压缩和解压缩

    linux下文件的压缩和解压缩 目录 1.压缩 2.解压缩 3.归档工具 一. 压缩 compress: -d:解压缩,相当于uncompres-c:结果输出至标准输出,不删除原文件-v:显示详情 - ...

  9. Qt中用QuaZip来压缩和解压缩文件

    1.简介 QuaZIP是使用Qt,C++对ZLIB进行简单封装的用于压缩ZIP以及解压缩ZIP的开源库.如果你的Qt项目当中用到了压缩以及解压缩ZIP的话你可以考虑选择使用它. 官方主页:http:/ ...

  10. Centos之压缩和解压缩命令

    常用压缩格式:.zip .gz .bz2 常用压缩格式:.tar.gz  .tar.bz2 1.zip格式压缩 zip压缩文件名 源文件 压缩文件 zip -r 压缩文件名 源目录 压缩目录 [roo ...

最新文章

  1. 莫斯科保卫战之PHP-502 Bad Gateway
  2. vs调试按钮为灰色的_IntelliJ IDEA 调试 Java 8,实在太香了
  3. 计算机网络第二章-物理层
  4. 理解至上:数位dp(ybtoj-B数计数)
  5. 【Kaggle】Intermediate Machine Learning(XGBoost + Data Leakage)
  6. 微信授权获取用户openid前端实现
  7. ASH的适用场景和常见用法(附2个经典案例)
  8. 力扣第202题. 快乐数(JavaScript)
  9. 大话云上“分布式实践”,理解 B、A、C 并不难!
  10. python爬虫入门实战之爬取美国体育网篮球比赛数据(selenium+xpath)
  11. LINUX内核内存屏障
  12. 堆排序-Java小顶堆排序
  13. 【Other】希腊诸神大全-中英文名称
  14. 今日金融词汇--- 商业模式
  15. ko 绑定html,WeX5的正确打开方式(3)——绑定机制
  16. 3d 角色血条制作方案:解决近大远小的策略
  17. 【从0到1搭建LoRa物联网】18、LoRa应用服务器Application Server
  18. NPE和CPE的区别
  19. 身体质量指数程序,入门写死的小程序项目
  20. Centos7 deploy mongoDB Replica set

热门文章

  1. 对抗机器学习:Generating Adversarial Malware Examples for Black-box Attacks Based on GAN
  2. 常见职位的英文简称_各种职位的英文简称都是什么?
  3. [益智]:如果你有两个桶,一个装的是红色的颜料,另一个装的是蓝色的颜料。
  4. 电脑版工作提醒软件哪个好用?支持备忘提醒的电脑便签
  5. SQL Server数据库简介
  6. 手机office不登录 手机office不联网 手机office查询功能
  7. 解决JS在controll层定义带循环的公共方法,组件中调用时取不到返回值的问题
  8. 实战总结(二)—— CheckBox复选框和SpannableString
  9. Windows平台的原始套接字编程的知识点概要(备忘)
  10. erlang nif 测试