转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/50331883

<勿在浮沙筑高台>

LZW压缩算法原理很easy,因而被广泛地採用,已经被引入主流图像文件格式中。

该算法由Lempel-Ziv-Welch三人发明,这样的技术将定长码字分配给变长信源符号序列,它不须要知道被压缩文件的符号出现概率的先验知识,仅仅须要动态地建立和维护一个字典,和其它压缩算法相比既是缺点也是长处。

1. LZW原理

1.1 概念的理解

LZW通过建立一个字典(code table),把不认识的字符串序列增加字典。当下次再次遇到此种字符串序列时,用字典的索引序号取代此序列,而一个索引序号占用的字节数往往比取代的字符串小的多,以此来达到压缩文件的目的。通常在图像压缩上,因为0-255用于表示灰度级(8位二进制),而我们的索引序号要与灰度级差别开来,因而。字典索引的建立要从256開始,见以下的样例,此样例不表示LZW算法的原型,临时不要关心字典是怎样建立的。

        

注意到,在上图中,压缩文件里保存了123 256 119 ... ,因为文件数据都是採用二进制形式保存的,解压时为了正确的按位读取。通常压缩文件里,写入的每个数据都是以12位形式写入文件。这时用字典索引號256取代连续的字符序列145 201 4,就是用了12位的数据取代了3个8位的数据。尽管其它的字符以原型写入,比如第一个8位数据123被扩展成12位的123,可是整体上看,仍然达到了压缩的作用。

1.2 压缩过程&流程图

     LZW算法採用动态的建立字典的方法,依次读入原文件的字符序列,每次碰到新的连续的字符串。就在字典中增加标示。当下次再次遇到这样的字符串时,就能够用字典索引序号直接取代字符串,写入压缩文件里。在这里引入两个名词: "string","char";string表示前缀。char 表示新读入的字符,每一个字典索引相应一对(string,char);

--------------------------------------------------------------------------------------------------------------------------------------

举个样例:“ABCABC”開始时。初始化字典,索引0~255被初始化为(NULL, i), i =0,1,...,255;让字典从索引號256開始记录,正如上面所说。为了解压时方便识别数据,每次向压缩文件里写数据时,都是12位格式。这时字典索引范围为0~4095;

1. 開始时,读入第一个字符string = A,读下一个字符char = B 。

3. 查字典(A,B),字典中没有找到,在字典索引256中记录(A,B),然后输出前缀A,更新string=char=B,再次读入字符,char=C;

4. 查字典(B,C),字典中没有找到,在字典索引257中记录(B,C),然后输出前缀B,更新string=char=C,再次读入字符。char=A;

5. 查字典(C,A),字典中没有找到,在字典索引258中记录(C,A),然后输出前缀C,更新string=char=A,再次读入字符,char=B;

     6. 查字典(A,B),字典能够找到,相应索引號256,然后更新string=256,再次读入字符,char=C;

7. 查字典(256,C),字典中没有找到,在字典索引259中记录(256,C),然后输出前缀256,更新string=char=C,再次读入字符。char=NULL;

8. char = NULL
,文件结束,输出前缀C.

压缩完毕后:A B C
256 C ; 字典不须要写入文件里;

上述过程概括:"前缀string+字符char"在字典中不存在,增加字典。输出前缀,更新前缀=char,读入新字符char;

"前缀string+字符char"在字典中存在,更新前缀=索引號,读入新字符char;

-------------------------------------------------------------------------------------------------------------------------------------- 
  



   1.3 解压过程&流程图

   
上述压缩文件为 A B C 256 C ,相同採用上述的步骤。初始化字典,建立字典、查字典的方法能够实现文件的解压缩,可是解压缩过程并不简单等同于压缩过程。解压缩完毕后压缩文件时建立的字典和解压缩建立的字典全然一样。PS:解压缩过程。网上部分博客说法不准确,结果导致我折腾了两天程序 。

------------------------------------------------------------------------------------------------------------------------------------------------

OCODE:表示已经读入的12位数据 ; NCODE:表示新读入的12位数据。

STRING:表示12位数据代表的字符串。CHAR表示被写入文件的字符串的第一个字符;

1. 開始时,初始化字典(0~255),读入第一个数据OCODE = A,输出字典索引OCODE相应的字符串A。读下一个数据NCODE = B 。

2. NCODE在字典中存在,输出table[NCODE]=B,CHAR=B;在字典索引256增加(OCODE,CHAR)=(A,B),更新OCODE=NCODE,读取数据NCODE=C;

3. NCODE在字典中存在,输出table[NCODE]=C,CHAR=C;在字典索引257增加(OCODE,CHAR)=(B,C),更新OCODE=NCODE,读取数据NCODE=256。

4. NCODE在字典中已建立,table[256]=AB,并记录CHAR=A;在字典索引258增加(OCODE,CHAR)=(C,A),更新OCODE=NCODE,读取数据NCODE=C;

5. NCODE在字典中已建立,table[NCODE]=C,CHAR=C。在字典索引259增加(OCODE,CHAR)=(256,C),更新OCODE=NCODE读取数据NCODE=空。

6. 文件结束!跳出循环!

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

你肯定已经注意到,上面举得样例解压缩时读取的NCODE都能够在字典中找到,什么情况下在字典中找不到呢?

压缩这个字符串"ABBBBBBBB"。解压缩时就能够碰到字典中找不到的情况。一定要动手试试,方便你理解整个流程图!

2.关于LZW的使用和改进

   上面的样例都是採用12位格式写入文件,可是12位在字典中表示的范围为0~4095,真实去压缩一个文件时,这个大小肯定是不够的,假设扩展字典的范围,占用内存非常大。可是这时能够在文件里增加一个标示。然后又一次初始化字典,表示从此開始。採用新字典继续压缩文件。能够理解成把文件切割成多个小文件,每一个小文件单独採用一张表。通常令256表示新表的開始,257表示文件压缩结束。

从上面的过程能够看到,每个数据都採用12位格式写入文件。无疑造成了内存的浪费,比如256实际上能够用9位二进制表示。所以有非常多人对此进行了改进。採用变长的字典算法。比如当9位的字典写满时。继续採用10位的字典压缩。同一时候也有多算法对查找字典的方法进行了改进,时间上也有非常大的提高!

3.LZW算法的实现

完整project下载:http://download.csdn.net/detail/luoshixian099/9369093

/**********************************
CSDN 勿在浮沙筑高台
http://blog.csdn.net/luoshixian099
【数据压缩】LZW压缩算法 2015年12月17日
***********************************/
#include <iostream>
#include <fstream>
#include "Compress.h"
using namespace std;
#define IN "D:\\my.bmp"
#define OUT "D:\\test.rar"
int main()
{
compress COM(IN,OUT);
if (!COM.CheckFile())
return 0;
COM.Intial(); //压缩初始化
COM.WriteChar(START); //写入開始标志
UINT pre_code = COM.ReadChar();//读取前缀
UINT Count = 0;
while (!COM.CheckEOF())
{
UINT code = COM.ReadChar(); //读入新字符
UINT temp = COM.CheckTable(pre_code, code);//查字典
if (temp == EMPTY)
{
COM.WriteChar(pre_code); //写入前缀
pre_code = code; //更新前缀
}
else if (temp == NEW_TABLE) //字典已满,又一次初始化字典
{
COM.WriteChar(pre_code);
COM.WriteChar(NEW_TABLE);
COM.Intial();
pre_code = code;
}
else
{
pre_code = temp;
}
}
COM.WriteChar(pre_code); //文件结束,输出前缀
COM.WriteEnd();
return 0;
}
/**********************************
CSDN 勿在浮沙筑高台
http://blog.csdn.net/luoshixian099
【数据压缩】LZW解压缩算法 2015年12月17日
***********************************/
#include <iostream>
#include <fstream>
#include "decompress.h"
using namespace std;
#define IN "D:\\test.rar"
#define OUT "D:\\mytest.bmp"
int main()
{
DeCompress DCOM(IN,OUT);
if (!DCOM.CheckFile())
return 0;
DCOM.Intial(); //初始化字典
UINT OCODE, NCODE;
UCHAR FirstChar;
OCODE = DCOM.ReadData(); //读取第一个数据
DCOM.WriteChar(OCODE); //输出 while (!DCOM.CheckEOF())
{
NCODE = DCOM.ReadData(); //读入新数据
if (NCODE == END) //文件结束标志
break;
else if (NCODE == NEW_TABLE) //读入新字典标志
{
OCODE = DCOM.ReadData();
DCOM.WriteChar(OCODE);
DCOM.Intial();
continue;
}
if (DCOM.CheckTable(NCODE)) //在字典中存在
{
DCOM.WriteChar(NCODE); //输出NCODE
FirstChar = DCOM.GetFirstChar(NCODE);//更新NCODE的第一个字符
}
else //字典中不存在
{
DCOM.WriteChar(OCODE);
DCOM.WriteChar(FirstChar);
FirstChar = DCOM.GetFirstChar(OCODE);
}
DCOM.AddtoTable(OCODE, FirstChar); //OCODE+CHAR字典
OCODE = NCODE;
}
DCOM.WriteEnd();
return 0;
}

參考文章:

http://blog.chinaunix.net/uid-23741326-id-3124208.html

http://blog.csdn.net/abcjennifer/article/details/7995426

【数据压缩】LZW算法原理与源代码解析的更多相关文章

  1. Android源代码解析之(三)--&gt;异步任务AsyncTask

    转载请标明出处:一片枫叶的专栏 上一篇文章中我们解说了android中的异步消息机制. 主要解说了Handler对象的使用方式.消息的发送流程等.android的异步消息机制是android中多任务处 ...

  2. 【数据压缩】LZ78算法原理及实现

    在提出基于滑动窗口的LZ77算法后,两位大神Jacob Ziv与Abraham Lempel [1]于1978年又提出了LZ78算法:与LZ77算法不同的是LZ78算法使用树状词典维护历史字符串. [ ...

  3. 机器学习算法实现解析——word2vec源代码解析

    在阅读本文之前,建议首先阅读"简单易学的机器学习算法--word2vec的算法原理"(眼下还没公布).掌握例如以下的几个概念: 什么是统计语言模型 神经概率语言模型的网络结构 CB ...

  4. GBDT算法原理深入解析

    GBDT算法原理深入解析 标签: 机器学习 集成学习 GBM GBDT XGBoost 梯度提升(Gradient boosting)是一种用于回归.分类和排序任务的机器学习技术,属于Boosting ...

  5. 【数据压缩】LZ77算法原理及实现

    1. 引言 LZ77算法是采用字典做数据压缩的算法,由以色列的两位大神Jacob Ziv与Abraham Lempel在1977年发表的论文<A Universal Algorithm for ...

  6. 2. Attention Is All You Need(Transformer)算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  7. 3. ELMo算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  8. 4. OpenAI GPT算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  9. 5. BERT算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

随机推荐

  1. PHP设置会话(Session)超时过期时间实现登录时间限制[转]

    用户登录系统60分钟后如果没有操作就自动退出 第一种方法即设置php.ini配置文件,设置session.gc_maxlifetime和session.cookie_lifetime节点属性值,当然也 ...

  2. 【模式匹配】更快的Boyer

    1. 引言 前一篇中介绍了字符串KMP算法,其利用失配时已匹配的字符信息,以确定下一次匹配时模式串的起始位置.本文所要介绍的Boyer-Moore算法是一种比KMP更快的字符串匹配算法,它到底是怎么快 ...

  3. Elasticsearch 删除索引下的所有数据

    下面是head中操作的截图 #清空索引 POST quality_control/my_type/_delete_by_query?refresh&slices=5&pretty { ...

  4. Scrapy实战篇(四)之周杰伦到底唱了啥

    从小到大,一直很喜欢听周杰伦唱的歌,可是相信很多人和我一样,并不能完全听明白歌词究竟是什么,今天我们就来研究一下周董最喜欢在歌词中用的词,这一小节的构思是这样的,我们爬取周杰伦的歌词信息,并且将其进行 ...

  5. tomcat8.5请求参数限制的问题

    前段时间遇到这个问题: 包含json字符串类型的参数的http请求失败,返回状态码400,提示invalid character found in the request target. Tomcat ...

  6. HDU 1287 MC挖矿世界 set bfs

    MC挖矿世界 题目连接: http://acm.uestc.edu.cn/#/problem/show/1287 Description 银牌爷和柱神开始玩MC啦,但是怪物实在是太多了,于是银牌爷决定 ...

  7. 一步一步创建JAVA线程

    (一)创建线程 要想明白线程机制,我们先从一些基本内容的概念下手. 线程和进程是两个完全不同的概念,进程是运行在自己的地址空间内的自包容的程序,而线程是在进程中的一个单一的顺序控制流,因此,单个进程可 ...

  8. PHP 日期的加减

  9. system.ComponentModel.Win32Exception (0x80004005): 目录名无效。 解决方法

    有时候我们需要在程序中调用 cmd.exe  执行一些命令 比如 我们会在程序写到 /// <summary> /// 执行Cmd命令 /// </summary> /// & ...

  10. mui中a标签的跳转问题

    一.脑补 快速响应是mobile App实现的重中之重,研究表明,当延迟超过100毫秒,用户就能感受到界面的卡顿,然而手机浏览器的click点击存在300毫秒延迟(至于为何会延迟,及300毫秒的来龙去 ...