1、LZ77是基于字典的算法,和霍夫曼编码不同,其处理的符号不一定是文本字符,可以是任何大小的符号。
2、LZ77使用前向缓冲区(待编码区的小段)和一个滑动窗口(搜索区)实现。滑动窗口是个历史缓冲器,它被用来存放输入流的前n个字节的有关信息。前向缓冲区是与动态窗口相对应的,它被用来存放输入流的前n个字节。常用滑动窗口4KB,前向缓冲区32B
   算法主要思想就是在前向缓冲区中不断寻找能够与字典中短语匹配的最长短语。如果匹 配的数据长度大于最小匹配长度,那么就输出一对〈长度,距离滑动窗中对应的位置〉数组。长度(length)是匹配的数据长度,而距离(distance)说明了在输入流中向后多少字节这个匹配数据可以被找到。
   LZ77算法中代价最高的是滑动窗口中扫描匹配短语。一个更高效的方法是用某种高效搜索性能的数据结构代替滑动窗口。
   LZ77比霍夫曼编码有更好的压缩比,但是压缩过程中LZ77要消耗相当长的时间。

   如果前向缓冲区包含A、B、D那么缓冲区就包含了短语{(A),(A,B)(A,B,D)}
   如果滑动窗口中包含A、B、C那么窗口和字典中短语为{(A),(A,B)(A,B,C),(B),(B,C),(C)}

3、基本流程
(1) 、从当前压缩位置开始,考察未编码的数据,并试图在滑动窗口中找出最长的匹配字符串,如果找到,则进行步骤 2 ,否则进行步骤 3.
(2) 、输出三元符号组( off,len,c )。其中 off 为窗口中匹配字符串相对窗口边界的偏移,len为可匹配的长度,c 为下一个字符,即不匹配的第一个字符。然后将窗口向后滑动 len+1 个字符,继续步骤 1.
(3) 、输出三元符号组( 0,0,c )。其中 c 为下一个字符。然后将窗口向后滑动一个字符,继续步骤 1.

3、最长字符串匹配

//从window中匹配buffer中最长字符串;offset返回window中匹配首位置;next返回buffer字符串后不匹配第一个字符位置
//返回匹配最长字符串的长度
static int compare_win(const unsigned char *window, const unsigned char *buffer, int *offset, unsigned char *next)
{int match, longest, i, j, k;*offset = 0;longest = 0;*next = buffer[0];//最外面循环在window中第1个字符-第n个字符,第2个-第n个一个....., 第n-1个到第n个 for(k = 0; k < LZ77_WINDOW_SIZE; k++){i = k;j = 0;match = 0;//在最外层循环的一个中找buffer能匹配的最长字符串 (从buffer第一个符号开始) while(i < LZ77_WINDOW_SIZE && j < LZ77_BUFFER_SIZE - 1){if(window[i] != buffer[j])break;//match统计目前匹配的长度 match++;i++;j++;} //保存返回信息 if(match > longest){*offset = k;longest = match;*next = buffer[j]}}return longest;
}

4、LZ77压缩

int lz77_compress(const unsigned char *original, unsigned char **compressed, int size)
{unsigned char window[LZ77_WINDOW_SIZE], buffer[LZ77_BUFFER_SIZE], *comp, *temp, next;int offset, length, remaining, hsize, ipos, opos, tpos, i;int token, tbits;//初始化 *compressed = NULL;memset(window, 0, LZ77_WINDOW_SIZE);memset(buffer, 0, LZ77_BUFFER_SIZE);//向头信息中写入源数据字节数 hsize = sizeof(int);comp = (unsigned char *)malloc(hsize);memcpy(comp, &size, sizeof(int)); ipos = 0;//ipos指向源数据中正在处理的字节//从源数据中取数据到缓冲区中 for(i = 0; i < LZ77_BUFFER_SIZE && ipos < size; i++){buffer[i] = original[ipos];ipos++;} opos = hsize * 8;//opos是压缩数据bit的位置 remaining = size;while(remaining > 0){//标记 = type + offset(在window中) + length + next //next就是不匹配的字符  //tbit表示生成标记长度 if((length = compare_win(window, buffer, &offset, &next)) != 0){//能找到type为1 token = 0x0000_0001 << (LZ77_PHRASE_BITS - 1);token = token | (offset << LZ77_PHRASE_BITS - LZ77_TYPE_BITS - LZ77_WINOFF_BITS);token = token | (length << LZ77_PHRASE_BITS - LZ77_TYPE_BITS - LZ77_WINOFF_BITS - LZ77_BUFLEN_BITS);token = token | next;tbits =  LZ77_PHRASE_BITS;}else{//没找到 ,标记就是原符号 token = 0x0000_0000;token = token | next;tbits = LZ77_SYMBOL_BITS;} //s数据处理为大端模式 token = htonl(token);//往压缩区填数据for(i = 0; i < tbits; i++){if(opos % 8 == 0){temp = (unsigned char *)realloc(comp, (opos / 8) + 1);comp = temp;}//根据长度tbits取一位一位压缩tpos = (sizeof(unsigned long) * 8) - tbits + i; bit_set(comp, opos, bit_get((unsigned char *)&token, tpos));} length++;//length是匹配数据字节长度//左移更新window把buffer中以编码的字符移到window memmove(&window[0], &window[length], LZ77_WINDOW_SIZE - length); memmove(&window[LZ77_WINDOW_SIZE - length], &buffer[0], length);//更新buffer中内容,做移除已经编码的字符,从源数据中调入新字符 memmove(&buffer[0], &buffer[length], LZ77_BUFFER_SIZE - length);for(i = LZ77_BUFFER_SIZE - length; (i < LZ77_BUFFER_SIZE) &&(ipos < size); i++){buffer[i] = original[ipos];ipos++;}remaining = remaining - length;} *compressed = comp;return ((opos - 1) / 8) + 1;
}

5、LZ77解压

int lz77_uncompress(const unsigned char *compressed, unsigned char **original)
{unsigned char window[LZ77_WINDOW_SIZE], buffer[LZ77_BUFFER_SIZE];unsigned char *orig, *temp, next;int offset, length, remaining, hsize, size, ipos, opos, tpos, state, i;*original = orig = NULL;//从压缩数据头信息中读出源数据字节数 hize = sizeof(int);memcpy(&size, compressed, sizeof(int));memset(window, 0, LZ77_WINDOW_SIZE);memset(buffer, 0, LZ77_BUFFER_SIZE);ipos = hsize * 8;opos = 0;remaining = size;while(remaining > 0){//先读出type,看是否为window中字符 state = bit_get(compressed, ipos);ipos++;if(state == 1){//读出offset到offset中 memset(&offset, 0, sizeof(int));    for(i = 0; i < LZ77_WINOFF_BITS; i++){tpos = (sizeof(int) * 8) - LZ77_WINOFF_BITS + i;bit_set((unsigned char *)&offset, tpos, bit_get(compressed, ipos));ipos++;}//读出length到length中 memset(&length, 0, sizeof(int));    for(i = 0; i < LZ77_BUFLEN_BITS; i++){tpos = (sizeof(int) * 8) - LZ77_BUFLEN_BITS + i;bit_set((unsigned char *)&offset, tpos, bit_get(compressed, ipos));ipos++;}//读出nextnext = 0x00; for(i = 0; i < LZ77_NEXT_BITS; i++){tpos = (sizeof(int) * 8) - LZ77_NEXT_BITS + i;bit_set((unsigned char *)&next, tpos, bit_get(compressed, ipos));ipos++;}offset = ntohl(offset);length = ntohl(length);i = 0;//解压时ipos是压缩数据对应的bit位;//opos是解压后数据的第几字节 //为这个字串申请空间 if(opos > 0){temp = (unsigned char *)realloc(orig, opos + length + 1);orig = temp;}elseorig = (unsigned char *)malloc(length + 1);//标记 = type + offset(在window中) + length + next //解码 offset(在window中) + length对应字串while(i < length && remaining > 0){orig[opos] = window[offset + i];opos++;buffer[i] = window[offset + i];i++;remaining--;} //存入next if(remaining > 0){orig[opos] = next;opos++;buffer[i] = next;remaining--; }length--;} //是源字符 else{next =0x00;//读出源字符给next for(i = 0; i < LZ77_NEXT_BITS; i++){tpos = (sizeof(unsigned char) * 8) - LZ77_NEXT_BITS + i;bit_set((unsigned char *)&next, tpos, tpos, bit_get(compressed, ipos));ipos++;} if(opos > 0){temp = (unsigned char *)realloc(orig, opos + 1);orig = temp;}elseorig = (unsigned char *)malloc(1);orig[opos] = next;opos++;if(remaining > 0)buffer[0] = next;remaining--;length = 1;}//根据buffer更新window,这里的buffer为每次读到的数据,第一次更新一次memmove(&window[0], &window[length], LZ77_WINDOW_SIZE - length);memmove(&window[LZ77_WINDOW_SIZE - length], &buffer[0], length); } *original = orig;return opos;
}

23、LZ77压缩和解压相关推荐

  1. Linux常用的压缩和解压命令gzip,gunzip,tar,zip, unzip和bzip2,bunzip2

    Linux常用的压缩和解压命令 1.压缩解压gzip和gunzip 特点: 压缩比例大概为6:1 该命令只能压缩文件,不能压缩目录 压缩或者解压后不保留源文件 压缩示例:gzip 需要压缩的文件 解压 ...

  2. 文件的压缩和解压等操作

    .1.将文件压缩为zip/rar文件(实质都为zip格式) /*** 创建ZIP文件* @param sourcePath 文件或文件夹路径* @param zipPath 生成的zip文件存在路径( ...

  3. 哈夫曼编码实现文件的压缩和解压

    哈夫曼编码的概念 哈夫曼编码是基于哈夫曼树实现的一种文件压缩方式. 哈夫曼树:一种带权路径最短的最优二叉树,每个叶子结点都有它的权值,离根节点越近,权值越小(根节点权值为0,往下随深度增加依次加一), ...

  4. 利用python中的gzip模块压缩和解压数据流和文件

    直接给出源码实现, 分为两种情况: 1.网络连接中的数据流的压缩和解压,或是打开的文件读取一部分 2.打开文件压缩或是解压 #!/usr/bin/env python #encoding: utf-8 ...

  5. Qt qCompress和qUncompress 压缩和解压文件

    利用Qt的qCompress和qUncompress来压缩和解压文件 有个特点,用qCompress压缩的文件不能直接用别的软件来解压,需要经过处理,否则只能利用Qt的qUncompress来解压,因 ...

  6. python解压文件_使用Python实现文件压缩和解压

    大家可能都熟悉.zip格式的文件.它可以把多个文件,压缩成一个文件.这在网络上传输时很有用,而且节省硬盘空间. 接下来,我们使用Python实现压缩和解压. 读取ZIP文件信息 要读取ZIP文件的内容 ...

  7. Unity BZip2压缩和解压,基于C#

    基于BZip2的压缩方式(ICSharpCode.SharpZipLib)   压缩和解压代码举例: MemoryStream ms = new MemoryStream();         BZi ...

  8. linux为什么用tar压缩,linux下tar压缩和解压命令用法详解

    linux下tar压缩和解压命令用法详解 2017-03-25 14:06 分享人:老牛 将/usr/local/test目录下所有文件仅打包,不压缩到 /usr/local/auto_bak/目下 ...

  9. Jpeglib使用指南, 各种压缩包的压缩和解压方法, 开源社区分裂史

    http://antkillerfarm.github.io/ Jpeglib使用指南 1.问题的由来 Jpeg图片在图像处理领域已经用的相当广泛了.但在编程领域,尤其是嵌入式编程领域使用的还不是很广 ...

最新文章

  1. (转)jLink使用ITM机制实现调试stm32单片机
  2. 美国燃油管道商认怂,俄罗斯黑客收到500万美元赎金!,民众为抢汽油大打出手...
  3. java得出两个日期之间所有日期
  4. Android Studio 第六十五期 - Android业务组件库
  5. 数据库面试题目经典大全
  6. 近100个Spring/SpringBoot常用注解汇总!
  7. linux core文件乱码,.net core在linux下图片中文乱码
  8. 杭电3068 最长回文 最长回文的manacher算法
  9. 并发数 = QPS*平均响应时间(转)
  10. Builder创建者模式
  11. 光模块基础知识【快速入门】02
  12. 图神经网络-图游走类模型-作业
  13. 初生牛犊不怕虎 —— 独自背井离乡
  14. 百度文库 -3ds max
  15. 【索引分类】位图索引
  16. NMOS管和PMOS管做开关控制电路
  17. 科学计算线性方程组的几个实例
  18. 【大数据之 Flume】入门到放弃
  19. 谁在使用Linux?
  20. 破、立、行,网贷雷潮背后的消亡与新生 | 一点财经

热门文章

  1. python report_ReportPortal(自动化报表统一平台)的搭建与python推送
  2. [Hadoop基础]-- Hadoop namenode的HA搭建
  3. UG\NX二次开发 菜鸟欢乐多
  4. 解锁“不可能”:苏门答腊犀牛让我开始重新思考AI
  5. QMUI-Android的一些尝试(圆形进度条、Loading、圆形图片、圆形按钮、椭圆图片)
  6. python网络爬虫(第八章:图像识别与文字处理)
  7. 区块链编程语言_区块链解决方案开发的编程语言
  8. 小红书批量发布帖子笔记软件怎么用
  9. python初级教练员考试题目_JS | 教练,我想做习题8
  10. Spark日志,及设置日志输出级别