转载请注明出处: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. [SPOJ SEQN] [hdu3439]Sequence

    题目就是求C(n,k)*H(n - k)%m 0<= k<= n <=10^9, 1 <= m <= 10^5, n != 0 其中H(n)是错排第n项. 对于C(n,k ...

  2. luogu P1919 【模板】A*B Problem升级版(FFT快速傅里叶)

    模板 嗯 做多项式乘法,进位 没了 #include<cmath> #include<cstdio> #include<cstring> #include<a ...

  3. BZOJ 2612 [Poi2003]Sums(最短路)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2612 [题目大意] 给定a数组,问num能否被表示为a[1]*x[1]+a[2]*x[ ...

  4. 【最小表示法】BZOJ2176-Strange string(unsigned char!!!)

    [题目大意] 给定一个字符串S = {S1, S2, S3 … Sn}, 如果在串SS中, 子串T(|T| = n)为所有长度为n的SS的字串中最小的(字符串的比较), 则称T为”奇怪的字串”. 你的 ...

  5. 2017-2018-1 JAVA实验站 冲刺 day03

    2017-2018-1 JAVA实验站 冲刺 day03 各个成员今日完成的任务 小组成员 今日工作 完成进度 张韵琪 写博客.进行工作总结 100% 齐力锋 部分按钮图片.对按钮图片进行ps 100 ...

  6. bzoj 2152

    /************************************************************** Problem: 2152 User: idy002 Language: ...

  7. ACM -- 算法小结(八)字符串算法之Manacher算法

    字符串算法 -- Manacher算法 首先介绍基础入门知识,以下这部分来着一贴吧,由于是很久之前看的,最近才整理一下,发现没有保存链接,请原创楼主见谅. //首先:大家都知道什么叫回文串吧,这个算法 ...

  8. apose 根据excel 导出模版

    string file = Server.MapPath("~/Excel/ZWxxtj.xls");            DataSet ds = new DataSet(); ...

  9. 用python slearning类库实现数据挖掘(python3.x)

    Summary of test0 data : source data source code : in test0 file reference : - Reference Website / - ...

  10. C# httpwebrequest post 传输百分号‘%’

    转载:http://blog.csdn.net/qqstrive/article/details/8229601 通过webrequest的post传输数据的时候,如果url里面的参数带有‘%’,那么 ...