[Estructura de datos] Códec de árbol de Huffman [Diseño del curso]

(Nota:

Este código se completa usando vc ++ 6.0, y algunos mecanismos de juicio interno de diferentes compiladores pueden ser diferentes, lo que hace que el código no se ejecute normalmente.

Copie este código directamente, definitivamente habrá un problema, la razón es cómo se opera el archivo, si no tiene una base básica en absoluto, no se recomienda leer este blog)

!!! Una explicación más detallada se encuentra en los comentarios del código a continuación. Si hay un problema con el programa, verifique si el nombre del archivo correspondiente es correcto.

¡Por fin, buena suerte, vamos! ! !

 

Metas del plan de estudios:

                             

Función función del plan de estudios: 

                                             

(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()函数为程序的入口,这个就不在详说了

 

 Código del curso:

//注:	
//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");
}

 

 Preparación previa de documentos:

 

 

La captura de pantalla del resultado en ejecución es la siguiente:

 

 

 

 

 

 

 

 

 

                          Espero que pueda ser útil para usted, gracias por mirar, si cree que es útil para usted, por favor déle me gusta, gracias por su apoyo 

Supongo que te gusta

Origin blog.csdn.net/L_Z_jay/article/details/111993209
Recomendado
Clasificación