转载请注明出处: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. Appium robotframework-appium (ios 客户端测试)环境搭建

    一. 简介 1.1摘要 本人测试新人,最近在搞ios客户端的自动化,准备采用robotframework-appium来实现自动化测试,一边学习一边总结,此安装说明文档是基于mac系统10.11版本, ...

  2. cocos2d-android 使用 cocos2d 绘图

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha cocos2d-android-1 https://github.com/ZhouWei ...

  3. Palindromic Tree 回文自动机-回文树 例题+讲解

    回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同 ...

  4. 「UOJ207」共价大爷游长沙

    「UOJ207」共价大爷游长沙 解题思路 : 快速判断两个集合是否完全相等可以随机点权 \(\text{xor}\) 的思路可以用到这道题上面,给每一条路径随机一个点权,维护出经过每一条边的点权的 \ ...

  5. bzoj 2055: 80人环游世界 -- 上下界网络流

    2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MB Description     想必大家都看过成龙大哥的<80天环游世界>,里面 ...

  6. [转][Android] ListView中getView的原理+如何在ListView中放置多个item

      ListView 和 Adapter 的基础 工作原理: ListView 针对List中每个item,要求 adapter “给我一个视图” (getView). 一个新的视图被返回并显示 如果 ...

  7. hdu 5210 delete 水题

    Delete Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5210 D ...

  8. Linux下简单分析请求有没有进到本机的工具tcpdump(网络接口的数据包的头信息)

    可以通过这个工具快速分析出一个请求到底有没有进入到本机.信息有点简单,对于前期的分析比较有帮助.而对于详细的分析可以借助iptables的raw表进行日志分析. 参考: http://man.linu ...

  9. JSoup 用法详解

    清单 1 // 直接从字符串中输入 HTML 文档 String html = "<html><head><title> 开源中国社区 </titl ...

  10. SpringMvc的服务器端跳转和客户端跳转

    首先,找到 package org.springframework.web.servlet.view; public class InternalResourceViewResolver extend ...