[データ構造]ハフマンツリーコーデック[コースデザイン]

(注意:

このコードはvc ++ 6.0を使用して完成し、コンパイラーごとに内部判定メカニズムが異なる場合があり、コードが正常に実行されない場合があります。

このコードを直接コピーすると、間違いなく問題が発生します。理由は、ファイルの操作方法です。基本的な基盤がまったくない場合は、このブログを読むことはお勧めしません)

!!!より詳細な説明は、以下のコードコメントにあります。プログラムに問題がある場合は、対応するファイル名が正しいかどうかを確認してください。

最後に、頑張ってください、さあ!

 

カリキュラムの目標:

                             

カリキュラムの機能機能: 

                                             

(1) int  read_File( )   //读文件操作

(2) void  calculate(int chWeight[], int reRow)  //源文件中字符的频度是多少

(3) void  createHuffmantree(Huffman ht[], int chWeight[], int n) //创建哈夫曼树
    1) void  select (Huffman ht[], int n, int *s1, int *s2) 
                 //建立哈夫曼树,每次查找没有双亲结点且是最小的两个数

(4) void  huffmanCode(Huffman tree[], codetype code[], int n)  //对各个字符进行编码

(5) void huffmanTrans(codetype *code , int n)   //对输入的字符进行编码并保存到文件中
    1)    //将输入的字符串进行编码,
          //打印编码结果
          //并将编码结果存储进文件中
        void  memory_File(codetype *code , char b[],int n)
    2)    //将输入的字符串进行编码,
          //打印编码结果
        void printCode(codetype *code , char b[],int n)

(6)void huffDecode(codetype *code, int n) //对某个文件进行译码,并将译码的结果存储在另一个文件中


***main()函数为程序的入口,这个就不在详说了

 

 コースコード:

//注:	
//system("pause"); 作用:是让程序暂时暂停,当你在有新的指令时,才会进行下一步
//本文传值的数字7的含义:我是从下标为0开始存储字符,且文件中只有ABCDEFG这几种字符
//若你无法解决数字7,欢迎留言,我尽力解答
//若你想了解更多,欢迎留言
//有任何的问题,都欢迎您的留言,谢谢
//我会将我所用到的文件等信息展示出来,希望可以帮助到你
//最后,谢谢您的观看!!!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 50 
typedef struct node{
	int Weight;     //代表字符的权重
	char ch;        // 代表的是哪个字符
	int Parent;     // 双亲结点
	int Lchild;     // 左孩子
	int Rchild;     // 右孩子
}Huffman;
typedef struct code{
	char bits[N];   //字符的编码串
	int start;      //编码在位串中的起始位置
	char ch;        //存储的字符是谁?
}codetype;
int flag=0;         //判断读文件是否是首次进入读文件函数的
char container[100][100];     //从源文件中读出的内容 
char ex_container[100][100];  // 从文件中读出需要译码的内容
void select (Huffman ht[], int n, int *s1, int *s2);
void memory_File(codetype *code, char b[] ,int n);
void printCode(codetype *code, char b[] ,int n);
int  read_File( ){
		FILE *fp;
		int len,i=0;	
		//flag的作用是判断是否是首次进入读文件函数,
		//理由:因为题目的要求是我们要从文件中获取字符并统计其出现的频度
		if(flag == 0){	
			flag = 1;
			//这里是打开01.souce.txt,这个是我本机上的文件,你可能没有,
			//而且我这里用的是相对路径,相对的意思就是相对代码文件的位置在什么地方
			//如果不能正确写出来,可以在下方留言,我会尽快解答
			fp = fopen("01.souce.txt","r+");
				if(fp == NULL){
					printf("文件打开失败");
					return 0;
				}
				else
				{
					printf("恭喜恭喜,文件成功打开!!!\n");
					printf("这样您就可以进行后续步骤啦!!!\n");
					//读文件成功
					//每行的最大字符
					//这里为什么这样写请自行百度查查fgets()函数的用法和作用
					//每次读取的是一行的内容
						while(fgets(container[i],100,fp) != NULL){
								len = strlen(container[i]);
								if(i<2){
									container[i][len-1] = '\0';
								//	printf("%d %d\n",container[i][len-1],len);
								}
								/*else{

									printf("%d %d\n",container[i][len-1],len);
								}*/	
								i++;
							}
					printf("\n");
					fclose(fp);
					system("pause");
					return i-1;
					
				}
		}
		else{
				//这个是打开的是里边存的是一些有效编码的文件
				fp = fopen("explain.code.txt","r+");
				if(fp == NULL){
					printf("文件打开失败");
					return 0;
				}
				else
				{
					printf("打开成功\n");
					//读文件成功
					//每行的最大字符
					//只能实现单行文本的读取
					//每次读取的是一行的内容
					while(fgets(ex_container[i],100,fp) != NULL){
						len = strlen(ex_container[i]);
						//printf("%c",ex_container[i][len-1]);
						i++;
					}
					printf("\n");
					fclose(fp);
					system("pause");
					return i-1;
					
				}
			}
}
void  calculate(int chWeight[], int reRow){
		int i,j,k;
		int len;
		for(i = 0;i <= reRow;++i){
				len = strlen(container[i]);
				for(j = 0;j < len ;++j){
					k = (int)(container[i][j] - 'A');
					chWeight[k]++;
				}
		}
		printf("各个字符的详细情况如下表示 :\n");
		printf("\t-----\n");
		printf("\t|字符|权重|\n");
		printf("\t-----\n");
		for(i = 0;i<7;i++){
			printf("\t|%2c | %2d |\n",('A'+i),chWeight[i]);
			printf("\t-----\n");
		}
		system("pause");
}
void  createHuffmantree(Huffman ht[], int chWeight[], int n){
		int m,i;
		int s1,s2;
		m = 2*n-1;
		//创建哈夫曼树
		for(i = 0;i < n;++i){
			ht[i].Weight = chWeight[i];
			ht[i].ch = 'A'+i;
			ht[i].Parent = -1;
			ht[i].Lchild = -1;
			ht[i].Rchild = -1;
		}
		for(i = n;i < m;++i){
			ht[i].Weight = 0;
			ht[i].ch = '0';
			ht[i].Parent = -1;
			ht[i].Lchild = -1;
			ht[i].Rchild = -1;
		}
		for(i = n;i<m;i++){
			select(ht,i-1,&s1,&s2);
			ht[i].Weight = ht[s1].Weight + ht[s2].Weight;
			ht[i].Lchild = s1;
			ht[i].Rchild = s2;
			ht[s1].Parent = i;
			ht[s2].Parent = i;
		}
		printf("创建完成\n");
		system("pause");
}
//字符的编码,规定左'0'右'1'
void  huffmanCode(Huffman tree[], codetype code[], int n){
		 int i,c,p;
		 codetype cd;  
		 for(i=0;i<n;i++)
		 {
		  cd.start=n;
		  cd.ch=tree[i].ch;
		  c=i;       //从叶结点出发向上回溯
		  p=tree[i].Parent;   //tree[p]是tree[i]的双亲
		  while(p!=-1)
		  {
		   cd.start--;
		   if(tree[p].Lchild==c)
			cd.bits[cd.start]='0';  //tree[i]是左子树,生成代码'0'
		   else
			cd.bits[cd.start]='1';   //tree[i]是右子树,生成代码'1'
		   c=p;
		   p=tree[p].Parent;
		  }
		  code[i]=cd;    //第i+1个字符的编码存入code[i]
		 }
		 printf("字符编码完成\n");
		 system("pause");
}
void huffmanTrans(codetype *code , int n){
		char b[100];
		int choice;
		getchar();
		printf("请输入字符串(由A-G范围的字符组成)\n");
		gets(b);
		printf("是否要将编译结果存储的文件中(1-存入文件,0-不存储)\n");
		scanf("%d",&choice);
		getchar();
		if(choice == 1){
			memory_File(code,b,n);
		}
		else if(choice == 0){
			printCode(code,b,n);
		}
		else{
			printf("非法输入,请重新进入!!!\n");
		}
		system("pause");
}
//字符译码
void huffDecode(codetype *code, int n){
	int row;
	int m;
	int i=0,j=0;
	int star;
	FILE *fp;
	row = read_File();
	//这里是文件中存在编码,我们需将它转变成相应的字符的转换过程,请独立看懂并理解
	//如果有更好的思路,欢迎下方留言,谢谢!!!
	for(i = 0;i < n;++i){
		star = code[i].start;
		if(code[i].bits[star] == ex_container[0][j]){
			m = j;
			for(j = j+1 ,star = star+1;(j < strlen(ex_container[0]) && star < n); star++,j++){
					if(code[i].bits[star] != ex_container[0][j])
							break;
				}
			if(star == n){
					fp = fopen("explain.decode.txt","a");
					if(fp == NULL)
						printf("文件打开失败,请重新尝试一次!!!");
					else{
						printf("%c ",code[i].ch);
						fprintf(fp,"%c",code[i].ch);
						i = -1;
						fclose(fp);
					}
			}
			else{
				j = m;
			}
		}
			
	}
	printf("\n");
	system("pause");
		
}

int main (void){
		int i,j;
		int n,reRow;
		int chWeight[10] = {0};
		Huffman ht[N];
		codetype huffCode[N];
		while(1){
			printf("\t\t\t   ***********************************\n");
			printf("\t\t\t   *1-读文件操作\t\n");
			printf("\t\t\t   *2-计算源文件中字符出现的频度\t\n");
			printf("\t\t\t   *3-建立哈夫曼树\t\n");
			printf("\t\t\t   *4-对字符编码\t\n");
			printf("\t\t\t   *5-对输入的字符进行编码并存进文件\t\n");
			printf("\t\t\t   *6-对文件进行译码并将结果存进文件\t\n");
			printf("\t\t\t   ***********************************\n");
			printf("请输入你所要进行的操作(1-6):");
			scanf("%d",&n);
			switch(n){

				case 1:  reRow = read_File();//读取文件中的内容
					     break;
				case 2:  calculate(chWeight,reRow);//统计源文件中的各个字符的频度
					     break;
				case 3:  createHuffmantree(ht,chWeight,7);//创建哈夫曼树
						 printf("恭喜恭喜,哈夫曼树创建完成!!!\n");
						 //printf("\t*******************************\n");
						 printf("-------------------\n");
						 printf("|下标|字符|权重|父结点|左结点|右结点|\n");
						 for(i = 0;i<13;++i){
							 //printf("\t*******************************\n");
							 printf("-------------------\n");
							 printf("|%3d |%3c |%3d |%4d  |%4d  |%4d  |\n",i,ht[i].ch,ht[i].Weight,ht[i].Parent,ht[i].Lchild,ht[i].Rchild);
							
						 }
						 printf("打印结束,真不错!!!\n\n");
						 system("pause");
					     break;
				case 4:  huffmanCode(ht,huffCode,7);//对各个字符进行编码
						 printf("恭喜恭喜,字符编码成功,结果如下:\n");
						 printf("\t-------\n");
						 printf("\t|字符 |编码 |\n");
						 printf("\t-------\n");
						 for(i = 0;i < 7;++i){
							 printf("\t|%3c  |",huffCode[i].ch);
								 for(j=huffCode[i].start;j<7;j++)
								    	printf("%c",huffCode[i].bits[j]);
								printf("\n\t-------\r");
							 printf("\n");
						 }
						 system("pause");
						 break;
				case 5:  huffmanTrans(huffCode,7);//对输入的字符进行编码并保存到文件中
					     break;
				case 6:	 huffDecode(huffCode,7);//对某个文件进行译码,并将译码的结果存储在另一个文件中
						 break;
				default :
						 printf("无效输入!!!请输入(1-6)的数字\n");
						 return -1;
			}
		}
		return 0;
}
//建立哈夫曼树,每次查找没有双亲结点且是最小的两个数
void  select (Huffman ht[], int n, int *s1, int *s2){
		int i,j,f = 1;
		int sum;
		for(i = 0;i < n;++i){
			for(j = i+1;j <= n;++j){
				if(ht[i].Parent != -1)
					continue;
				else{
					if(ht[j].Parent == -1){
						if(f == 1){
							sum = ht[i].Weight + ht[j].Weight;
							f = 0;
							*s1 = i;
							*s2 = j;
						}
						else {
								if((ht[i].Weight + ht[j].Weight) < sum){
									sum = ht[i].Weight + ht[j].Weight;
									*s1 = i;
									*s2 = j;
								}
						}
					}
				}
			}
		}
		//交换*s1和*s2的值,使前者始终指向权重较小的下标
		if(ht[*s1].Weight > ht[*s2].Weight){
			*s1 = *s1 + *s2;
			*s2 = *s1 - *s2;
			*s1 = *s1 - *s2;
		}
}
//将输入的字符串进行编码,
//打印编码结果
//并将编码结果存储进文件中
void  memory_File(codetype *code , char b[],int n){
		int i,j=0,k;
		FILE *fp;
		fp = fopen("written.code.txt","w");
		if(fp == NULL){
			printf("文件打开失败,请重新尝试!!!");
		}
		else{
			printf("编码结果如下:\n");
			for(i=0;i<n;i++){
				if(j < strlen(b)){
						if(b[j]==code[i].ch){
							for(k=code[i].start;k<n;k++){
								printf("%c",code[i].bits[k]);
								fprintf(fp,"%c",code[i].bits[k]);
							}	
							printf(" ");
							j++; i=-1;
						}
					}
			}
			printf("\n编码结果已成功存进文件!!!\n");
				
		}
		fclose(fp);
		system("pause");
	
}
//将输入的字符串进行编码,
//打印编码结果
void printCode(codetype *code , char b[],int n){
		int i,j = 0,k;
		printf("编码结果如下:\n");
		for(i=0;i<n;i++){
			if(j < strlen(b)){
					if(b[j]==code[i].ch){
						for(k=code[i].start;k<n;k++)
								printf("%c",code[i].bits[k]);				
						j++; i=-1;
						printf(" ");
					}		
				}
		}	
		printf("\n编码结果已成功显示!!!\n");
}

 

 前提条件のドキュメントの準備:

 

 

実行結果のスクリーンショットは次のとおりです。

 

 

 

 

 

 

 

 

 

                          それがあなたに役立つことを願っています、見てくれてありがとう、あなたがあなたに役立つと思うなら、それを好きにしてください、あなたのサポートに感謝します 

おすすめ

転載: blog.csdn.net/L_Z_jay/article/details/111993209