LZW压缩算法是Unisys的专利,由Lempel-Ziv-Welch三人发明,有效期到2003年。
LZW思路:
ASCII字符有255个,每个用8bits表示,如果要表示2个字符,就用16bits;3个字符就用24bits,依此类推。假设我们对ASCII码扩展成12位,可以有4096个字符,并自己定义255以后的含义,如ab定义成258,abc定义成259,那么ab只用12位,较原来节约4位;abc也只用12位,较原来24bits节约12位,可以想象,代替的字符串越长,位数越节约。一般LZW压缩比为2:1或3:1。这是以前系统内存以及存储能力较小,为提高计算和存储能力而设计的。到现在,计算机性能突飞猛进,其优势就不复存在。
LZW核心是在于其压缩算法——动态生成压缩字典,自动还原压缩字典进行解压,压缩数据内含压缩字典,边压缩边生成压缩字典,但不保存;解压时,边解压边还原压缩字典,进行解压。
压缩
生成压缩字典就是如何将255个的ASCII码动态扩展成4096个字符码的过程。
(1)形成关键字为255个ascii码,值为0~255的初始字典,设定clearcode=256,endcode=257。(clearcode是为了在解压时避免扩展字典容量超过4096时,告诉程序以后的压缩数据的压缩字典重新计算;endcode表示结束)
(2)读取一个字符(input),和根字符(root)形成新的字符串(key),如果新字符串(key)在字典里存在,将根字符用新字符串(key)取代;如果key不存在,则将root计入输出流,input计为root字符,在字典关键字中添加Key,以及递增的值。
以ababababa为例,演示其压缩过程:
步骤 |
数据流 (Input) |
根字符 (Root) |
关键字字符 (Key=Root+Input) |
字典 (Diction) |
输出流 (Output) |
|
1 |
a |
|
a |
- |
- |
a在字典中,root=a |
2 |
b |
a |
ab |
[ab]=258 |
97(a) |
ab不在字典,将ab作为字典关键字,值自动加1=258,a输出,b=>root |
3 |
a |
b |
ba |
[ba]=259 |
98(b) |
添加ba,输出b,a=>root |
4 |
b |
a |
ab |
- |
- |
ab存在字典,ab=》root |
5 |
a |
ab |
aba |
[aba]=260 |
258(ab) |
aba不存在,添加关键字aba,输出关键字ab的值258,a=》root |
6 |
b |
a |
ab |
- |
- |
ab存在字典,ab=》root |
7 |
a |
ab |
aba |
- |
- |
aba存在字典,aba=》root |
8 |
b |
aba |
abab |
[abab]=261 |
260(aba) |
abab不存在,添加关键字abab,输出关键字aba的值260,b=》root |
9 |
a |
b |
ba |
- |
- |
ba存在字典,ba=》root |
10 |
EOF |
ba |
|
|
259(ba) |
结束,输出关键字ba值 259 |
原值:97 98 97 98 97 98 97 98 97=》保存为8位二进制数据流:1100001 1100010 1100001 1100010 1100001 1100010 1100001 1100010 1100001,共72bits
压缩后的值:97 98 258 260 259=》保存为12位二进制数据流:00001100001 00001100010 000100000010 000100000100 000100000011,共60bits。
注:由于字典关键字个数小于4096,没有用到clearcdoe(256)。
解压
(1)同压缩,生成初始字典;
(2)读取一个字符(input)的第一个数值,在字典中找到对应的字符串输出,key字符=Root字符+input字符串第一个字符,并将key添加到字典中,将input设为新Root;
如果没有对应的关键字,key字符=Root+Root的第一个字符,并将key添加到字典中,输出key字符,将key设为新Root;
以上面压缩数据97 98 258 260 259 解压为例
步骤 |
数据流 (Input) |
根字符 (Root) |
关键字字符 (Key=Root+Input.FirstChar) |
字典 (Dictionary) |
输出流 (Output) |
说明 |
1 |
97 |
|
a |
- |
a |
a存在,输出97,a=》root |
2 |
98 |
a |
ab |
[258]=ab |
b |
98存在字典,输出98(b),b=>root,ab不存在,添加ab。 |
3 |
258(ab) |
b |
ba |
[259]=ba |
ab |
258存在,输出[258]=ab,ab=>root;ba不存在,添加ba, |
4 |
260 |
ab |
aba=ab+ab.firstchar |
[260]=aba |
aba |
260不存在字典,关键字=Root+Root.firstChar,添加到字典,并输出(这是lzw最巧妙的地方,没有在字典里,如何推算出260),aba=>root |
5 |
259(ba) |
aba |
abab |
[261]=abab |
ba |
259存在,输出[259]=ba,ba=》root,abab不存在,添加abab。 |
6 |
EOF |
ba |
|
|
- |
|
还原出a b ab aba ba。
注意:
压缩时,按8位一个字节读出;字典关键字是字符串,值为数值;
解压时,按12位读出;字典关键字是数字,值为字符串;
来源:CSDN
作者:lzljy
链接:https://blog.csdn.net/lzljy/article/details/103575209