实验三 LZW编码

实验目的:

掌握词典编码的基本原理,编程实现LZW解码器并分析编解码算法。

实验原理:

在这里插入图片描述

实验过程:

#include <stdlib.h>
#include <stdio.h>
#include “bitio.h”
#define MAX_CODE 65535

struct {
int suffix;
int parent, firstchild, nextsibling;
} dictionary[MAX_CODE+1];
int next_code;
int d_stack[MAX_CODE];
#define input(f) ((int)BitsInput( f, 16))
#define output(f, x) BitsOutput( f, (unsigned long)(x), 16)

int DecodeString( int start, int code);
void InitDictionary( void);
void PrintDictionary( void){
int n;
int count;
for( n=256; n<next_code; n++){
count = DecodeString( 0, n);//count为所在层数(即该词条码元个数)
printf( “%4d->”, n);
while( 0<count–) printf("%c", (char)(d_stack[count]));
printf( “\n”);
}
}

int DecodeString( int start, int code){ //可找到上层母结点层数
int count;
count = start;
while( 0<=code){
d_stack[ count] = dictionary[code].suffix;//按照从叶向根的顺序将码元写入dstack(即数组下标低的存叶结点的字符,则print函数中count–可按正序输出码字)
code = dictionary[code].parent;//从下层向上寻找母结点
count ++;
}
return count;
}
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;

}

int InDictionary( int character, int string_code){//寻找string_code结点下值为character的孩子结点
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;
}

void AddToDictionary( int character, int string_code){//将stringcode+charactor送入词典
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){ // the parent has child
nextsibling = firstsibling;
while( -1<dictionary[nextsibling].nextsibling )
nextsibling = dictionary[nextsibling].nextsibling;
dictionary[nextsibling].nextsibling = next_code;
}else{// no child before, modify it to be the first
dictionary[string_code].firstchild = next_code;//string_code有孩子结点时,将next_code设置为string_code的最末一个孩子结点,若string_code没有孩子结点则将next_code设置为string_code的第一个孩子结点

}
next_code ++;

}

void LZWEncode( FILE *fp, BITFILE *bf){
int character;
int string_code;
int index;
unsigned long file_length;

fseek( fp, 0, SEEK_END);
//int fseek(FILE *stream,ling offset,int fromwhere)stream将指向以fromwhere为基准,偏移offset个字节的位置
file_length = ftell( fp);
fseek( fp, 0, SEEK_SET);
BitsOutput( bf, file_length, 4*8);//4*8为一个int字节的bit数,输出bf指向文件,每次输出一个int,输出filelength次
InitDictionary();
string_code = -1;
while( EOF!=(character=fgetc( fp))){
	index = InDictionary( character, string_code);//stringcode代表前缀串p,找p+c是否在词典中
	if( 0<=index){	// string+character in dictionary
		string_code = index;//将p+c送给p
	}else{	// string+character not in dictionary
		output( bf, string_code);//输出p对应码字
		if( MAX_CODE > next_code){	// free space in dictionary
			// add string+character to dictionary
			AddToDictionary( character, string_code);//将p+c送入词典
		}
		string_code = character;//将c作为新前缀p
	}
}
output( bf, string_code);//用来输出最后一个字符,如:abac,aba为词典中的字条,则执行操作时会将aba对应索引号输出,然后将abac作为新词条存入词典中,此时,若abac为结尾,则需将c单独编码输出

}

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);
if( -1 == file_length) file_length = 0;
/*需填充*/
InitDictionary();
last_code=-1;
while(file_length>0)
{
	if(last_code<0)
	{
		new_code=input(bf);
		phrase_length=DecodeString(0,new_code);
	}
	else
	{
		new_code=input(bf);
		if(new_code<next_code)//该码字在词典中
		{
			phrase_length=DecodeString(0,new_code);
			character=d_stack[phrase_length-1];
			if(MAX_CODE>next_code){AddToDictionary(character,last_code);}
		}
		else//该码字不在词典中
		{
			phrase_length=DecodeString(1,last_code);//预留出下标1的位置存放lastcode的首字符,由于DecodeString中count从1开始计数,故phraselength比lastcode的长度多一
			character=d_stack[phrase_length-1];
			if(MAX_CODE>next_code){AddToDictionary(character,last_code);}
			d_stack[0]=character;
		}
	}
	//输出当前码字
	while( 0<phrase_length)
	{
		phrase_length --;
		fputc( d_stack[ phrase_length], fp);
		file_length--;
	}
	last_code=new_code;
}

}

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");
	}
}else if( 'D' == argv[1][0]){	// do decoding
	bf = OpenBitFileInput( argv[2]);
	fp = fopen( argv[3], "wb");
	if( NULL!=fp && NULL!=bf){
		LZWDecode( bf, fp);
		fclose( fp);
		CloseBitFileInput( bf);
		fprintf( stdout, "decoding done\n");
	}
}else{	// otherwise
	fprintf( stderr, "not supported operation\n");
}
return 0;

}

实验结果:

TXT
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
LZW编码较为费时

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值