LZW算法
LZW编码算法,一种实现方式是对单一字符进行编码,压缩后数据需包含单一字符编码词典;另一种实现方式不需要包含词典,解压时由压缩后数据还原词典。 这里使用的是第二种实现方法,词典不需要同被压缩后的数据一同发送。这种方法中,0~255类似第一种实现方法中的单个字符词典;以下这段摘自维基百科
与霍夫曼编码相比,LZW编码被视作将不同长度字串以固定长的码编辑(霍夫曼编码将固定长度字元用不同长度的码编辑)。其优点在于此方法只需储存一个相当小的表格,即可储存资料还原时相对应的值,所以所需成本相对地低;然而,这种算法的设计著重在实现的速度,由于它并没有对数据做任何分析,所以并不一定是最好的演算法。
一些约定
因为LZW广泛用于GIF图片格式压缩,且可用于(可选)TIFF图片压缩,在GIF中使用的LZW压缩定义了256为CLEAR
,257为END
,这里遵循此约定;</br>
GIF中采用的编码长度为12位,LZW允许9位到16位可变,待实现时依据效率等因素调整
基本实现
压缩
每次读到下一个字符时,在编码表内查找当前的prevcode与当前字符,如果找到,则更新prevcode为找到的编码表位置,否则将prevcode和当前字符写入编码表下一个位置并更新prevcode为当前字符;编码表满后,写入CLEAR
,并重新初始化编码表;进行到文件末尾时,写入当前字符和END
。
解压缩
每次读到下一个编码时,判断该编码是否在0~255内</br>
如果在,则直接输出,并将前一个编码与其写入编码表下一个位置;</br>
如果不在,则再判断该编码是否在编码表内</br>
如果在,则输出其对应字符或字符串,输出时遇到0~255外的编码则继续向编码表内查找</br>
如果不在,则该字符串必然为其前一个编码所对应字符串+该字符串第一个字符</br>
遇到CLEAR
时,清空并重新初始化编码表,遇到END
时写入文件。
注意
这个笔记仅说明了LZW编码的原理,实际实现过程中可能还会遇到一些细节问题;在项目中,对于该算法可以根据需要进行相应改进
压缩和解压过程示例
编码 | 解码 | |||||||||
prevcode | 输入 | 位置 | prev | c | 输出 | 输入 | 位置 | prev | c | 输出 |
a | a | a | a | a | ||||||
a | b | 258 | a | b | a | b | 258 | a | b | b |
b | b | 259 | b | b | b | b | 259 | b | b | b |
b | a | 260 | b | a | b | 258 | 260 | b | 258 | ab |
a | b | 261 | 261 | 258 | 260 | aba | ||||
258 | a | 261 | 258 | a | 258 | c | 262 | 261 | c | c |
a | b | 257 | ||||||||
258 | a | |||||||||
261 | c | 262 | 261 | c | 261 | |||||
c | EOF | c |
编码 | 解码 | |||||||||
prevcode | 输入 | 位置 | prev | c | 输出 | 输入 | 位置 | prev | c | 输出 |
a | a | a | a | |||||||
a | b | 258 | a | b | a | b | 258 | a | b | b |
b | a | 259 | b | a | b | 258 | 259 | b | 258 | ab |
a | b | c | 260 | 258 | c | c | ||||
258 | c | 260 | 258 | c | 258 | d | 261 | c | d | d |
c | d | 261 | c | d | c | e | 262 | d | e | e |
d | e | 262 | d | e | d | f | 263 | e | f | f |
e | f | 263 | e | f | e | g | 264 | f | g | g |
f | g | 264 | f | g | f | 263 | 265 | g | 263 | ef |
g | e | 265 | g | e | g | g | 266 | 263 | g | g |
e | f | 257 | ||||||||
263 | g | 266 | 263 | g | 263 | |||||
g | EOF | g |