文章目录
数据压缩实验(三)
一、LZW概述
- 第二类词典编码——LZW
LZW属于第二类词典编码,其基本思想是:企图从输入的数据中创建一个“短语词典”,这种短语词典可以是任意字符的组合。编码数据过程中,当遇到已经在字典中出现的“短语”时,编码器就输出这个词典中的短语的“索引号”,而不是短语本身。
J.Ziv和A.Lempel在1978年首次发表了介绍第二类词典编码算法的文章。在他们的研究基础上,Terry A.Welch在1984年发表了改进这种编码算法的文章,因此把这种编码方法称为LZW(Lempel-Ziv Walch)压缩编码。
二、LZW编解码原理
1.LZW编码
(1)算法原理
代号代替短语:LZW的编码思想是不断地从字符流中提取新的字符串,通俗地理解为新“词条”,然后用“代号”也就是码字表示这个“词条”。这样一来,对字符流的编码就变成了用码字(code word)去替换字符(String),生成码字流且只输出码字流,从而达到压缩数据的目的。
动态生成词典,新词条等于旧词条加新字符:LZW编码需要从输入的数据中创建短语词典,LZW编码器通过管理这个词典完成输入(短语)与输出(短语的索引号)之间的转换。
词典在开始时初始化不能为空,必须包含字符流中所有单个字符,即在编码匹配时至少能找到长度为1的匹配串。
输入字符输出码字:LZW编码器的输入是字符流,字符流可以是用8位ASCII字符组成的字符串,而输出是用n位(例如12位)表示的码字流。
(2)算法流程
步骤1:将词典初始化为包含所有可能的单字符,当前前缀P初始化为空。
步骤2:当前字符 C = 字符流中的下一个字符。
步骤3:判断 P+C 是否在词典中:
1. 如果“是”,则用 C 扩展 P ,即令 P = P+C,返回步骤2。
2.如果“否”,则
(1) 输出与当前前缀 P 相对应的码字 W ;
(2) 将 P+C 添加到词典中;
(3) 令 P = C,并返回到步骤2。
具体如下图所示:
2.LZW解码
(1)算法原理
LZW解码算法开始时,译码词典和编码词典相同,包含所有可能的前缀根;
边解码边生成新词条,新词条等于旧词条加新字符。
(2)算法流程
步骤 1 :在开始译码时词典包含所有可能的前缀根。
步骤 2 :令 CW = 码字流中的第一个码字。
步骤 3 :输出当前字符串 CW 到码字流。
步骤 4 :先前码字 PW = 当前码字 CW 。
步骤 5 :当前码字 CW = 码字流的下一个码字。
步骤 6 :判断当前字符串 CW是否在词典中:
1. 如果 ” 是 ” ,则
(1) 把当前字符串 CW 输出到字符流;
(2) 当前前缀 P = 先前字符串 PW ;
(3) 当前字符 C = 当前字符串 CW 的第一个字符;
(4) 把字符串 P+C 添加到词典;
(5) PW = CW 。
2. 如果 ” 否 ” ,则
(1)当前前缀 P = 先前字符串 PW ;
(2) 当前字符 C = 当前字符串 CW 的第一个字符;
(3) 输出字符串 P+C 到字符流 , 然后把它添加到词典中;
(4) PW = CW 。
步骤7:判断码字流中是否还有码字要译:
1. 如果 ” 是 ” ,就返回步骤4。
2. 如果 ” 否 ”,则结束。
具体如下伪代码所示:
3.实验过程
(1)数据结构分析
尾缀字符(suffix) |
---|
母节点(parent) |
第一个孩子节点( firstchild ) |
下一个兄弟节点(nextsibling) |
树用数组dict[ ]表示,数组下标用pointer表示,所以dict[pointer]表示一个节点
dict[pointer].suffix
dict[pointer].parent
dict[pointer].firstchild
dict[pointer].nextsibling
(2)主函数
int main( int argc, char **argv){
FILE *fp;
BITFILE *bf;
if( 4 > argc){
fprintf( stdout, "usage: \n%s <o> <ifile> <ofile>\n", argv[0]);
fprintf( stdout, "\t<o>: E or D reffers encode or decode\n");
fprintf( stdout, "\t<ifile>: input file name\n");
fprintf( stdout, "\t<ofile>: output file name\n");
return -1;
}
if( 'E' == argv[1][0]){
// do encoding
fp = fopen( argv[2], "rb");
bf = OpenBitFileOutput( argv[3]);
if( NULL!=fp && NULL!=bf){
LZWEncode( fp, bf);
fclose( fp);
CloseBitFileOutput( bf);
fprintf( stdout, "encoding done\n&#