文章首发于我的个人博客
1. LZW基础概念
之前提到的算术编码、霍夫曼编码等技术集中在消除编码的冗余上,而本文要讲的LZW编码是一种针对空间冗余的无误差压缩方法。
LZW算法o又叫“串表压缩算法”,就是通过建立一个将字符串和其对应的记号构成的表(把已经出现过的字符串映射到记号上),用较短的代码来表示较长的字符串来实现压缩。
需要注意的是,LZW算法中字符串和记号的对应关系是在压缩的过程中动态生成的,并且隐含在压缩数据中,解压的时候也是一步一步还原编码并动态生成字典的过程。
2. LZW算法详解
2.1 LZW编码算法
编码器从字符串中不断地读入新的字符,并且将字符或字符串映射到新的记号,以动态地构建编码字典。在编码过程中,我们维护两个变量,即previous_char
(表示目前已有的,但未被编码的字符)和current_char
(表示刚刚读入的字符)。编码算法流程如下
- (1)初始状态,
previous_char
和current_char
都是空的。 - (2)读入新的字符current_char,并于previous合并成新的字符串
p_and_c
(previous_char+current_car) - (3)在编码字典里查找
p_and_c
,如果:p_and_c
在字典里,previous_char = p_and_cp_and_c
不在字典里,将previous_char
的标记输出;在字典中建立p_and_c
的映射;更新previous_char = current_char
。
- (4)返回步骤(2),重复直至读完字符串。
2.2 Example
ababcababac
初始状态字典里有三个默认的映射
String | Symbol |
---|---|
a | 0 |
b | 1 |
c | 2 |
开始编码
previous_char | current_char | p_and_c | p_and_c in dict | Action | output |
---|---|---|---|---|---|
“” | a | a | Y | previous_char = a | - |
a | b | ab | N | 添加映射{‘ab’, 3} previous_char = b | 0 |
b | a | ba | N | 添加映射{‘ba’, 4} | 1 |
a | b | ab | Y | previous_char = ab | - |
ab | c | abc | N | 添加映射{‘abc’, 5} previous_char = c | 3 |
c | a | ca | N | 添加映射{‘ca’, 6} previous_char = a | 2 |
a | b | ab | Y | previous_char = ab | - |
ab | a | aba | N | 添加映射{‘aba’, 7} previsou_char = a | 3 |
a | b | ab | Y | previous_char = ab | - |
ab | a | aba | Y | previous_char = aba | - |
aba | c | abac | N | 添加映射{‘abac’, 8} previous_char = c | 7 |
c | - | - | - | - | 2 |
编码结束,输出结果为0132372
,编码过程中生成的字典为: