Lab3 LZW 编解码算法实现与分析——C语言代码实现

本文详细介绍了LZW编解码算法的原理和C语言实现,包括编码、解码过程及数据结构分析。通过实验展示了算法在不同文件格式上的压缩效率,结果显示LZW算法在文字类文件上表现优秀,尤其对于重复性高的内容有较高压缩比。同时,文章指出LZW算法依赖于编解码两端词典的同步,但无需传递整个词典,降低了传输成本。
摘要由CSDN通过智能技术生成

Lab3 LZW 编解码算法实现与分析——C语言代码实现

一、实验步骤

  1. 首先调试LZW的编码程序,以一个文本文件作为输入,得到输出的LZW编码文件。
  2. 将得到的编码文件作为输入文件,编写LZW的解码程序。
  3. 选择至少十种不同格式类型的文件,使用LZW编码器进行压缩得到输出的压缩比特流文件,并对各种不同格式的文件进行压缩效率的分析。

二、实验原理

(一)编码原理

LZW算法编码基本思想:

  • 初始化包含单字符的词典表
  • 判断输入数据流中的当前字符串是否在词典表中
  • 若在词典中,则继续读取输入数据
  • 若不在词典中,则将当前字符串写入词典,分配一个新的数字索引号,生成新词条,便于下次使用
  • 将新写入的索引号进行输出,实现压缩目的,并继续读取输入数据
  • 循环判断,直至输入数据全部读取完毕

编码流程图
数据的重复性是算法实现的保证之一。

(二)解码原理

LZW算法解码基本思想:

  • 初始化包含单字符的词典表
  • 判断输入数据流中的当前字符串是否在词典表中
  • 若在词典中,则把当前字符串输出到字符流,并将先前字符串+当前字符串的第一个字符写入词典中
  • 若不在词典中,则把先前字符串+当前字符串的第一个字符进行输出,并将其写入词典中
  • 继续读取输入数据,循环判断,直至输入数据全部读取完毕

解码流程图1
解码流程图2
需要特别注意的是:
对于步骤6进行判断的第二种情况,即当前前缀-符串string.CW并不在词典中的情况,我们依然可以正确实现解码输出。

  • 出现这种情况的原因:在编码时,上一个刚创建的新词条直接被下一个词组所使用。
  • 算法的实现表明,解码端的词典建立会比编码端晚一步。
  • 处理这种情况的做法:由于下一个词条的尾缀必定是该词条的第一个字符,所以直接输出这个字符,然后再用先前一条词条的code进行译码即可。

三、程序实现

(一)数据结构分析

  • 树用数组dict[ ]表示,数组下标用pointer表示
  • dict[pointer]表示一个节点
  • dict[pointer].suffix表示尾缀字符
  • dict[pointer].parent表示母节点
  • dict[pointer].firstchild表示第一个孩子节点
  • dict[pointer].nextsibling表示下一个兄弟节点

(二)主要模块分析

1、初始化词典表

void InitDictionary( void){
	int i;

	for( i=0; i<256; i++){
		dictionary[i].suffix = i;
		dictionary[i].parent = -1;
		dictionary[i].firstchild = -1;
		dictionary[i].nextsibling = i+1;
	}
	dictionary[255].nextsibling = -1;
	next_code = 256;
}

2、查找字符串

int InDictionary( int character, int string_code){
	int sibling;
	if( 0>string_code) return character;
	sibling = dictionary[string_code].firstchild;
	while( -1<sibling){
		if( character == dictionary[sibling].suffix) return sibling;
		sibling = dictionary[sibling].nextsibling;
	}
	return -1;
}

3、在词典中写入新词条
写入新词条

4、编码实现函数
编码函数
5、解码实现函数

void LZWDecode( BITFILE *bf, FILE *fp)
{	//解码端实现函数
	int character;  //字符代号
	int new_code, last_code;  
	int phrase_length;  //字符串长度
	unsigned long file_length;  //文件长度

	file_length = BitsInput( bf, 4*8);  //根据传入参数bf计算有多少个字符
	if( -1 == file_length) file_length = 0;
	
	InitDictionary();  //初始化字典,为每个ASCII字符对应一个词条,即0-255个词条
	last_code = -1;  
	while( 0<file_length)  //判断输入的数据流是否已经全部读取完毕
	{
		new_code = input( bf);  //读取一个输入的索引号
		if( new_code >= next_code)  //将new_code与next_code进行比较,比较当前读取的索引号与词典目前最大索引号的大小关系
		//判断解码端收到的码字是否已经存在于字典中
		{ // this is the case CSCSC( not in dict) 解码端收到的码字不在字典中
			d_stack[0] = character;  //将当前字符代号写入堆栈,即当前字符串的尾缀更新为当前字符
			phrase_length = DecodeString( 1, last_code);  //解码得到字符
		}
		else
		{// 解码端收到的码字已经在字典中
			phrase_length = DecodeString( 0, new_code);  //解码得到字符
		}
		character = d_stack[phrase_length-1];  //更新堆栈,倒序存储,为写入新词条做准备
		while( 0<phrase_length)  //将字符串写入文本文件
		{
			phrase_length --;
			fputc( d_stack[ phrase_length], fp);
			file_length--;
		}
		if( MAX_CODE>next_code)  //当词典还有可写入新词条的内存空间时
		{// add the new phrase to dictionary
			AddToDictionary( character, last_code);
		}
		last_code = new_code;  //更新词典词条总数
	}
}

(三)实验结果

原文本文件lab6_test.txt
原文件
编码输出的压缩文件lab6_encode.txt
encode
解码得到的文本文件lab6_decode.txt
decode
由实验结果可知,编解码过程均正确。

四、压缩效率对比

选取十种不同格式类型的文件,使用LZW编码器进行压缩,计算压缩效率。
10种格式

文件格式压缩效率
1.txt0.6
2.pdf1.296
3.xlsx1.255
4.docx1.615
5.bmp0.272
6.jpg1.192
7.png1.267
8.avi1.194
9.mp41.237
10.html0.559
  • 总结:
  • LZW算法适合用于压缩较大的文字类型文件,且内容重复率越高,压缩效率越大。
  • LZW算法的实现基础在于编解码两端词典表的创建。
  • LZW算法不需要将词典表传送至解码端,从而避免了因词典表的内容过大,导致压缩失效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值