5、LZW编解码

目录

一、实验目的

二、实验原理

1. LZW编码原理

2. LZW解码原理

三、实验代码

1. 数据结构分析

2. 主要功能模块

(1)初始化词典

(2)将新串加入词典

(3)查找词典中是否有字符串

(4)编码

(5)解码

3.完整代码

(1)bitio.h

(2)bitio.c

(3)lzw.c

四、实验步骤

1. 调试编码程序

2. 调试解码程序

3. 压缩效率分析


一、实验目的

掌握词典编码的基本原理,用C/C++/Python等语言编程实现LZW解码器并分析编解码算
法。


二、实验原理

1. LZW编码原理

① 将词典初始化为包含所有可能的单字符,当前前缀P初始化为空。
② 当前字符C=字符流中的下一个字符。
③ 判断P+C是否在词典中
    1° 如果“是”,则用C扩展P,即让P=P+C,返回到步骤2。
    2° 如果“否”,则输出与当前前缀P相对应的码字W;
                              将P+C添加到词典中;
                              令P=C,并返回到步骤2。

2. LZW解码原理

① 在开始译码时词典包含所有可能的前缀根。
② 令CW:=码字流中的第一个码字。
③ 输出当前缀-符串string.CW到码字流。
④ 先前码字PW:=当前码字CW。
⑤ 当前码字CW:=码字流的下一个码字。
⑥ 判断当前缀-符串string.CW 是否在词典中。
    1° 如果”是”,则把当前缀-符串string.CW输出到字符流;
                        当前前缀P:=先前缀-符串string.PW;
                        当前字符C:=当前前缀-符串string.CW的第一个字符;
                        把缀-符串P+C添加到词典。
    2°  如果”否”,则当前前缀P:=先前缀-符串string.PW;
                          当前字符C:=当前缀-符串string.CW的第一个字符;
                          输出缀-符串P+C到字符流,然后把它添加到词典中。


三、实验代码

1. 数据结构分析

struct {
	int suffix;//尾缀字符
	int parent, firstchild, nextsibling;//母节点,第一个孩子节点,下一个兄弟节点
} dictionary[MAX_CODE+1];
int next_code;
int d_stack[MAX_CODE]; // stack for decoding a phrase

2. 主要功能模块

(1)初始化词典

void InitDictionary(void) {//将0~255根节点初始化
	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;//新词条从256开始编码
}

(2)将新串加入词典

void AddToDictionary(int character, int string_code) {
	int firstsibling, nextsibling;
	if (0 > string_code) return;//当前词条无前缀,为单个字符,已存在词典中
	dictionary[next_code].suffix = character;
	dictionary[next_code].parent = string_code;
	dictionary[next_code].nextsibling = -1;
	dictionary[next_code].firstchild = -1;
	firstsibling = dictionary[string_code].firstchild;//当前前缀的第一个孩子
	if (-1 < firstsibling) {	// 如果当前前缀有孩子
		nextsibling = firstsibling;
		while (-1 < dictionary[nextsibling].nextsibling) //只要nextsibling还有下一个兄弟
			nextsibling = dictionary[nextsibling].nextsibling;
		dictionary[nextsibling].nextsibling = next_code;
	}
	else {// 当前前缀无孩子,则新节点为它的第一个孩子
		dictionary[string_code].firstchild = next_code;
	}
	next_code++;
}

(3)查找词典中是否有字符串

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;//如果此孩子节点的尾缀字符等于character,则当前词条在词典中,返回此孩子节点
		sibling = dictionary[sibling].nextsibling;//否则,找当前前缀的下一个孩子节点
	}
	return -1;//没有找到,返回-1
}

(4)编码

void LZWEncode( FILE *fp, BITFILE *bf){
	int character;//当前字符C
	int string_code;//前缀P
	int index;//索引
	unsigned long file_length;//文件长度

	fseek( fp, 0, SEEK_END);//文件指针置于文件末尾
	file_length = ftell( fp);//获取文件长度
	fseek( fp, 0, SEEK_SET);//文件指针置于文件头
	BitsOutput( bf, file_length, 4*8);
	InitDictionary();//初始化词典
	string_code = -1;
	while( EOF!=(character=fgetc( fp))){
		index = InD
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值