closed
logo logo
关于我们

技术分享

技术分享 无损数据压缩LZW算法——C++实现

无损数据压缩LZW算法——C++实现

2021-05-13


无损数据压缩LZW算法


一、实验目的

1.掌握LZW算法的编码过程;

2.掌握LZW算法的译码过程。

 

二、实验设备与环境

Dev-C++ 5.9.2,Windows 7 操作系统

 

三、实验内容、程序清单及运行结果

实验要求:

Dev-C ++编写LZW算法程序。

1. 实现LZW编码程序。

2. 实现LZW解码程序。

实验参考步骤:

1.打开Dev-C ++,进入编程环境,新建一个源代码文件,文件名任意;

2.将下面我所编写的代码拷贝到所新建的源代码文件中;

3.点击编译运行。

 

 

C++源代码:

/**
*	作者:戴文治
*	时间:2017年11月3日
*	描述:LZW编码译码算法
*	特点:该代码具有可移植性,可在Dev-C++、VC++6.0、VS2010等多种平台完美运行
*		  该代码具有可重用性,运行后可对多个测试用例进行顺序测试而不受影响
*/
#include<iostream>
#include<cstring>
#define N 1000
using namespace std;
class LZW{ //LZW算法类
public:
	char encodeStr[N];		//要编码的字符串
	int decodeList[N];		//要译码的数组
	int firstDictionaryNum; //先前词典的大小 
	int length;				//当前词典的大小 
	char dictionary[N][N];	//先前词典
	
	
	LZW(){					//构造函数 
		encodeStr[0] = '\0';
		
		for(int i=0;i<N;i++){
			this->decodeList[i]=-INT_MAX;
		}
		
		for(int i=0;i<N;i++){
			this->dictionary[i][0] = '\0';
		}
		
		firstDictionaryNum = 0;
		length = 0;
	}
	
	
	bool initDictionary() 		//初始化先前词典
	{	
		if(encodeStr[0]=='\0'){			//若没有要编码的字符串,则不能生成先前词典 
			return false;
		}
		dictionary[0][0] = encodeStr[0];//将要编码的字符串的第一个字符加入先前词典 
		dictionary[0][1] = '\0';
		length = 1;
		int i,j; 
		for(i=1;encodeStr[i]!='\0';i++){//将要编码的字符串中所有不同的字符加入先前词典 
			for(j=0;dictionary[j][0]!='\0';j++){
				if(dictionary[j][0]==encodeStr[i]){
					break;
				}
			}
			if(dictionary[j][0]=='\0'){
				dictionary[j][0] = encodeStr[i];
				dictionary[j][1] = '\0';
				length++;
			}
		}
		firstDictionaryNum = length;			//先前词典的大小
		return true;
	}
	
	
	void Encode() 	 		 	//编码
	{
		for(int g=0;g<firstDictionaryNum;g++){	//先前词典中的初始编码没有输出编码,故设置为-1 
			decodeList[g]=-1;
		}
		int num = firstDictionaryNum;
		char *q,*p,*c;
		q =  encodeStr;						  	//q为标志指针,用来确认位置的 
		p =  encodeStr; 						//p指针作为字符串匹配的首字符 
		c = p;									//通过不断移动c指针实现匹配 
		while(p-q != strlen(encodeStr)){		//若还没匹配完所有字符,则循环 
			int i,j;
			int index=0;
			for(i=0;dictionary[i][0]!='\0'&&c-q!=strlen(encodeStr);i++){//通过不断向后移动c指针实现匹配
				char temp[N]; 
				strncpy(temp,p,c-p+1);			//每添加一个匹配字符,则已匹配字符串temp增加一个字符 
				temp[c-p+1]='\0';
				if(strcmp(temp,dictionary[i])==0){//字符匹配成功 
					c++;
					index = i;
				}
			}
			decodeList[num++]=index;			//遇到一个不匹配的字符或者已经没有字符可以匹配,则输出已匹配的字符串 
			if(c-q!=strlen(encodeStr)){			//若到一个不匹配的字符且还有字符未匹配,则说明出现了新的词典字段,加入词典 
				strncpy(dictionary[length],p,c-p+1);
				dictionary[length][c-p+1]='\0';
				length++;
			}
			p = c;								//匹配下一个时,p指向c的指向 
		}

	} 
	
	
	void Decode()    			//译码 
	{
		for(int i=1;decodeList[i]!=-INT_MAX;i++){	//根据输入代码来循环 
			if(decodeList[i]<=length){				//若出现输入代码在先前词典可以找到,则输出上一个输出的全部+当前输出的第一个 
				strcpy(dictionary[length],dictionary[decodeList[i-1]-1]);
				char temp[2];
				strncpy(temp,dictionary[decodeList[i]-1],1);
				temp[1]='\0';
				strcat(dictionary[length],temp);
			}
			else{									//若出现输入代码在先前词典找不到,则输出上一个输出的全部+上一个输出的第一个 
				strcpy(dictionary[length],dictionary[decodeList[i-1]-1]);
				char temp[2];
				strncpy(temp,dictionary[decodeList[i-1]-1],1);
				temp[1]='\0';
				strcat(dictionary[length],temp);
			}
			length++;
		}
	}	
};


int main(){
	while(true){
		cout<<"\n\t1.编码\t\t2.译码\t\t3.退出\n\n";
		cout<<"请选择:";
		char x;
		cin>>x;
		LZW lzw;
		if(x=='1'){
			cout<<"请输入要编码的字符串:"<<endl<<endl;
			cin>>lzw.encodeStr;
			if(lzw.initDictionary()==false){
				cout<<"请先设置要编码的字符串encodeStr属性"<<endl;
			}
			lzw.Encode();	//开始编码
			cout<<endl<<"编码过程为:"<<endl<<endl;
			cout<<"\t索引号\t\t\t词典\t\t\t输出"<<endl;
			for(int i=0;i<lzw.length;i++){
				cout<<"\t"<<i+1<<"\t\t\t"<<lzw.dictionary[i]<<"\t\t\t";
				if(i>=lzw.firstDictionaryNum){
					cout<<lzw.decodeList[i]+1;
				}
				cout<<endl;
			}
			cout<<"\t-\t\t\t-\t\t\t"<<lzw.decodeList[lzw.length]+1<<endl<<endl<<endl;
		} 
		else if(x=='2'){
			cout<<"请按顺序输入初始先前词典:(例:1 A)(输入0结束)"<<endl;
			int tempNum;
			cin>>tempNum;
			int index = 1; 
			while(tempNum!=0){
				if(tempNum<0){
					cout<<"输入序号错误,重新输入该行"<<endl<<endl;
					getchar();//两个getchar()是删除掉该行已经输入的字符 
					getchar();
					cin>>tempNum;
					continue;
				}
				if(tempNum!=index){
					cout<<"请以递增顺序输入序号,重新输入该行"<<endl<<endl;
					getchar();
					getchar();
					cin>>tempNum;
					continue;
				}
				cin>>lzw.dictionary[tempNum-1];
				cin>>tempNum;
				index++; 
			}
			lzw.firstDictionaryNum = index-1;
			lzw.length = lzw.firstDictionaryNum; 
			
			cout<<endl<<"请输入要译的编码(输入0结束):"<<endl<<endl;
			int temp;
			int j=0;
			cin>>temp;
			while(temp!=0){
				if(temp<0){
					cout<<"输入要译的编码错误,重新输入该编码"<<endl<<endl;
					cin>>temp;
					continue;
				}
				lzw.decodeList[j] = temp;
				j++;
				cin>>temp;
			}
			lzw.Decode();	//开始译码 
			cout<<endl<<"译码过程为:"<<endl<<endl;
			
			cout<<"    输入代码\t\t索引号\t\t词典\t\t输出"<<endl;
			for(int i=0;i<lzw.firstDictionaryNum;i++){
				cout<<"      \t\t\t   "<<i+1<<"  \t\t "<<lzw.dictionary[i]<<endl;
			}
			cout<<"\t"<<lzw.decodeList[0]<<"\t\t   -\t\t -\t\t  "<<lzw.dictionary[lzw.decodeList[0]-1]<<endl;
			for(int i=1;lzw.decodeList[i]!=-INT_MAX;i++){
				cout<<"\t"<<lzw.decodeList[i]<<"\t\t   "<<i+3<<"  \t\t "<<lzw.dictionary[i+3-1]<<"\t\t  "<<lzw.dictionary[lzw.decodeList[i]-1]<<endl;
			}
			cout<<endl<<endl;
		}
		else if(x=='3'){
			break;
		} 
		else{
			cout<<"请输入正确的选择!"<<endl<<endl<<endl;
		}
	}
	return 0;
}


测试用例1截图:

编码:

 无损数据压缩LZW算法——C++实现


译码:

无损数据压缩LZW算法——C++实现

 

测试用例2截图:

编码:

无损数据压缩LZW算法——C++实现

 

译码:

无损数据压缩LZW算法——C++实现



四、注意事项

注意指针的使用。

要求熟练掌握字符串处理函数,对这些函数的功能和效果要有很明确的意识,否则会出现很多BUG

最后,这次实验我遇见许多细微的问题,最后还是通过DEBUG调试才发现的。事实证明Dev-C++VC++非常地难以调试,很不直观!而用VS2010调试程序的话,它会有一个程序变量的窗口,每执行一条语句,它会显示出当前所有变量的值,还会把此次修改的变量用红色标注出来,在此推荐通过VS2010来调试程序。



云祺备份软件,云祺容灾备份系统,虚拟机备份,数据库备份,文件备份,实时备份,勒索软件,美国,图书馆
  • 标签:
  • 技术分享

您可能感兴趣的新闻 换一批

现在下载,可享30天免费试用

立即下载

请添加好友为您提供支持
jia7jia_7

请拨打电话
为您提供支持

400-9955-698