前言

  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());
    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 = 0
self.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 False def encoding(self):
step = 0
print("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 = 0
offset = 0
minEdge = 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 #每找到一个匹配串,加1 return (offset, matchLen) #入参字符串是否存在于搜索缓冲区,如果存在,返回匹配字符串的起始索引
def searchBufferOffest(self, i):
searchStart = self.getWinStartIndex()
searchEnd = self.windSpiltIndex
#下面几个if是处理开始时的特殊情况
if searchEnd < 1:
return self.notFind
if searchStart < 0:
searchStart = 0
if searchEnd == 0:
searchEnd = 1
searchStr = self.inputStr[searchStart : searchEnd] #搜索区字符串
findIndex = searchStr.find(self.inputStr[self.windSpiltIndex : i])
if findIndex == -1:
return -1
return len(searchStr) - findIndex #设置下一次窗口需要滑动的步数
def setMoveSteps(self, matchLen):
if matchLen == 0:
self.move = 1
else:
self.move = matchLen def minEdge(self):
return len(self.inputStr) if len(self.inputStr) - 1 < self.getWinEndIndex() else self.getWinEndIndex() + 1 def output(self, touple):
print("%d %d %s %s" % touple) if __name__ == "__main__":
lz77 = Lz77("AABCBBABC")
lz77.encoding()

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

参考文章:

  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. crawler_URL编码原理详解

    经常写爬虫的童鞋,难免要处理含有中文的url,大部分时间,都知道url_encode,各个语言也都有支持,今天简单整理下原理,供大家科普 1.特征: 如果URL中含有非ASCII字符的话, 浏览器会对 ...

  2. [转]utf8编码原理详解

    from : http://blog.csdn.net/baixiaoshi/article/details/40786503 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态 ...

  3. 块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

    CSS的可视化格式模型中具有一个非常重要地位的概念——定位方案.定位方案用以控制元素的布局,在CSS2.1中,有三种定位方案——普通流.浮动和绝对定位: 普通流:元素按照先后位置自上而下布局,inli ...

  4. SSL/TLS 原理详解

    本文大部分整理自网络,相关文章请见文后参考. SSL/TLS作为一种互联网安全加密技术,原理较为复杂,枯燥而无味,我也是试图理解之后重新整理,尽量做到层次清晰.正文开始. 1. SSL/TLS概览 1 ...

  5. [No0000126]SSL/TLS原理详解与WCF中的WS-Security

    SSL/TLS作为一种互联网安全加密技术 1. SSL/TLS概览 1.1 整体结构 SSL是一个介于HTTP协议与TCP之间的一个可选层,其位置大致如下: SSL:(Secure Socket La ...

  6. NFS原理详解

    NFS原理详解 摘自:http://atong.blog.51cto.com/2393905/1343950 2013-12-23 12:17:31 标签:linux NFS nfs原理详解 nfs搭 ...

  7. Netty学习——服务器端代码和客户端代码 原理详解

    服务器端代码和客户端代码 原理详解:(用到的API) 0.Socket 连接服务器端的套接字 1.TcompactProtocol   协议层2.TFrameTransport   传输层3.THsh ...

  8. I2C 基础原理详解

    今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...

  9. Zigbee组网原理详解

    Zigbee组网原理详解 来源:互联网 作者:佚名2015年08月13日 15:57   [导读] 组建一个完整的zigbee网状网络包括两个步骤:网络初始化.节点加入网络.其中节点加入网络又包括两个 ...

随机推荐

  1. 【分布式】Chubby与Paxos

    一.前言 在上一篇理解了Paxos算法的理论基础后,接下来看看Paxos算法在工程中的应用. 二.Chubby Chubby是一个面向松耦合分布式系统的锁服务,GFS(Google File Syst ...

  2. 你真的会玩SQL吗?简单的数据修改

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  3. MySQL的数据模型

    MySQL的数据类型主要分为三大类: 数值型(Numeric Type) 日期与时间型(Date and Time Type) 字符串类型(String Type) 1. 数值 MySQL的数值类型按 ...

  4. 通过NPOI操作Excel

    最近在做的一个项目中需要生成Excel,通过学习使用NPOI实现了相关需求,写了一个简便操作的类,记录如下: public class NPOIHelperForExcel { #region exc ...

  5. C# 视频编辑

    VidCoder VidCoder是一个开源免费的DVD/蓝光视频抓取和转码软件.使用HandBrake做为编码引擎.比Handbrake拥有更友好的用户界面. 可裁剪.剪切.字幕编辑.转码等. 官网 ...

  6. 8 种提升 ASP.NET Web API 性能的方法

    ASP.NET Web API 是非常棒的技术.编写 Web API 十分容易,以致于很多开发者没有在应用程序结构设计上花时间来获得很好的执行性能. 在本文中,我将介绍8项提高 ASP.NET Web ...

  7. vs2015 已经支持开发asp .net core 1.0 rc2 程序了

    vs2015 已经支持开发asp .net core 1.0 rc2 程序了 http://mp.weixin.qq.com/s?__biz=MzI0MzM1ODczOQ==&mid=2247 ...

  8. FastDFS 安装及使用

    FastDFS 安装及使用 2012-11-17 13:10:31|  分类: Linux|举报|字号 订阅     Google了一下,流行的开源分布式文件系统有很多,介绍如下:   mogileF ...

  9. Linux(九)__网络测试

    1.确认ip地址.子网掩码.网关是正确的. ifconfig 2.确认局域网是互通的,访问别人的电脑.网关 ping 发送数据包接收数据包,设备是否联通 /etc/sysconfig/network- ...

  10. java中如何实现多态

    复习基础知识 多态,就是重载和重写.重载发生在一个类中.重写发生在子类,意思就是子类重写父类相同名称的方法.刚学语言有的东西,不必搞得那么清楚,只有知道怎么用就行了,有的问题你要想真正把它搞得很懂,短 ...