赫夫曼编码课程设计--数据结构(C语言版)

题目:
试编写一个Huffman编码系统,用于数据加密和解密。该系统应具有以下功能:

  1. 初始化:从文本文档中可读取通信所使用的字符集和每个字符的权值。例如下表。
  2. 加密 :利用初始化中的数据建立Huffman树,对任意的可加密的字符串进行加密。
  3. 解密:对任何的加密结果进行解密。
    在这里插入图片描述
    扩展功能:
    支持从txt文本文档中读取一段文本(只包含26个小写英文字符和空格),并将文本中涉及到的所有字符统计频数,将频数作为权值构造哈夫曼树,并利用该哈夫曼树对此段文本加密、解密。

链接:https://pan.baidu.com/s/1lBM69P-7nKJ_Vsf_XjeVIw
提取码:zy09
(内附测试用TXT文件和项目源代码)

实现方式:
1.主界面:首先输入“1”选项导入存有各字符频次的TXT文件
在这里插入图片描述
文件内容如下
在这里插入图片描述
再重返主界面实现控制台输入字符串的加密解密操作

2.利用已有字符串建立Huffman树并在此基础上进行编码
在这里插入图片描述(以上述文字段为例建立Huffman树进行编码,进行后续加密解密操作)
tips:跪求一键三连!(小丑竟是我自己 具体的项目交流有需求+q:1297995979
源代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h> 
#include<conio.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX 27                  //26个英文单词加空格最多27个叶结点(有效结点) 
#define MAXNODE 53              //二叉树所有的结点数 

typedef int Status; 
typedef char* String;
typedef struct{
	int xb;
	char data;
	int weight;
	int parent,lchild,rchild;
}Node,*HuffmanTree;

typedef char **HuffmanCode; 
char lcode[MAX],rcode[MAX];
typedef int Status;

//赫夫曼树的创建  并且读取储存的初始化数据 
Status creatHuffman(HuffmanTree t){
	FILE *fp;
	int i=0,j;
	int w[MAX-1];
	char c[MAX-1],str[5];
	printf("\t\t\t开始读入\n");
	fp=fopen("Huffman Code Data.txt","r");
	while(!feof(fp)){	
		if(i==0){
			fscanf(fp,"%5s %d\n",&str,&w[i]);
			c[i]='#';
		}else{
			fscanf(fp,"%c %d\n",&c[i],&w[i]);
		}
		i++;
	}
	printf("\t\t\t初始化数据读取成功\n");
//	printf("排序\n");
	int k;char ch;
	for(i=0;i<MAX;i++){                       //将权重进行从小到大排序 
		for(int j=0;j<MAX-1;j++){
			if(w[j]>w[j+1]){ 
				k=w[j];w[j]=w[j+1];w[j+1]=k;               //同时交换字母与权重 
				ch=c[j];c[j]=c[j+1];c[j+1]=ch;
			}
		}
	} 
	for(j=0;j<(MAXNODE);j++){                                 //遍历一遍后将字母与相应权重赋值到t[]数组 
		if(j<MAX){
			t[j].data=c[j];
			t[j].weight=w[j];
			t[j].xb=j;
		}
		else{
			t[j].data='?';
			t[j].weight=0;
			t[j].xb=j;
		}
	}
	int front=0,rear=MAX-1;
	Node p;
	int xb;
	p=t[MAXNODE+1];
	while(front!=rear){                                             //处理27号结点之后原本为空的结点的内容 
		t[rear+1].data='?';
		t[rear+1].weight=t[front].weight+t[front+1].weight;         //暂存为相对应子节点的数值和,而后通过比较排序         
		rear=rear+1;
		for(i=rear;i>front+1;i--){
			if(t[i].weight<t[i-1].weight){                          //子节点相加之和最小的成为父节点 
				t[i].xb--;t[i-1].xb++;
				p=t[i];t[i]=t[i-1];t[i-1]=p;                        //交换并产生父节点 
				continue;
			}
			xb=i;                                                    //找到储存父节点的下标 
			break;
		}
		t[front].parent=xb;
		t[front+1].parent=xb;
		t[xb].lchild=t[front].xb;
		t[xb].rchild=t[front+1].xb;                                     //形成相应的左右子树 
		front=front+2;		
	} 
	for(j=0;j<(MAXNODE);j++){                                         //对没有数据的结点进行处理 
		if(t[j].data!='?'){
			t[j].lchild=t[j].rchild=-1;
		}
	} 
	t[rear].parent=-1; 
	return 1;
}
//整体输出每个字母相应的编码 
int creatCode(HuffmanTree t,HuffmanCode hc){
	int i;
	int cc;
	char str[MAX];
	str[MAX]='\0';
	char l[]="0";
	char r[]="1";
	int num=0;
	printf("打印所有字母对应的编码:\n");
	if(t[0].data==NULL){
		return FALSE;
	}		
	for(i=0;i<MAXNODE;i++){
		if(t[i].data!='?'){
			printf("%c",t[i].data);                           //打印本次循环的字母 
			memset(str,0,MAX);
			for(int c=i,f=t[i].parent;f!=-1;c=f,f=t[f].parent){
				if(t[f].lchild==c){         
					strcat(str,l);                            //字符串拼接 
				}else{
					strcat(str,r);
				}
			}
			for(num=0;str[num]!='\0';num++){				
			}                                        //num统计循环次数 
			if(t[i].data=='#'){
				cc=0;
			}else{
				cc=t[i].data-'a'+1;
			}
			hc[cc]=(char *)malloc(num*sizeof(char));
			char m;
			num--;
//			printf("开始逆序\n");
			for(int j=0;j<num;j++,num--){
				m=str[j];str[j]=str[num];str[num]=m;				
			}
//			printf("逆序:%s\n",str);
			strcpy(hc[cc],str);	
//			printf("编号:%d\n",cc);
			printf("编码:%s\n",hc[cc]);                                 //打印此字母的编码 
		}else if(i<MAX&&t[i].lchild==-1&&t[i].data=='?'){               //没有字母的编码的处理 
			hc[i]=(char *)malloc(sizeof(char));
		}
	}
	printf("创建Huffman编码成功\n");
	return TRUE;
}
//控制台输入文字的加密 
void enCode(HuffmanCode hc){
	printf("\t\t\t请输入要加密的字符串:");
	char ch[1000];
	getchar();
	gets(ch);
	int i,flag=0;
	for(i=0;ch[i]!='\0';i++){                        //遍历一遍统计次数 
		if(ch[i]==' '){
			continue;
		}
//		if(ch[i]<'a'||ch[i]>'z'){
//			flag = 1;
//			break;
//		}
	}
	printf("\t\t\t开始加密\n");	
	for(int j=0;j<i;j++){
		if(ch[j]==''&&!flag){		
			printf("\n待加密文件为空,加密失败\n"); 
			return ;
		}
		if(ch[j]==' '){
			printf("%s",hc[0]);
		}
		else if(ch[j]<'a' || ch[j]>'z'){
			flag = 1;
			printf("输入的数据不在已有数据范围内");
			break;
		}
		else if(ch[j]>='a'&&ch[j]<='z'){
			int k;
			k=ch[j]-'a'+1;
			printf("\t%s",hc[k]);
		}
	}
	printf("\n\t\t\t加密完毕\n");
	return ;
}
//控制台输入字符的解密 
void deCode(HuffmanTree t,HuffmanCode hc){
	char ch[1000];
	char str[MAX];
	str[MAX]='\0';
	char l[]="0";
	char r[]="1";
	int num=0;
	int max;
	for(int i=0;i<MAXNODE;i++){
		if(t[i].weight==0||t[i].data=='?'){                    //遍历一遍所有编码查询最长的编码长度 
			continue;
		}else{
			int k=t[i].data-'a'+1;
			if(t[i].data=='#'){
				max=strlen(hc[0]);
			}else{
				max=strlen(hc[k]);
			}
		}
	}
	
	int min=max;	
	memset(str,0,MAX);                                        //将0赋给MAX长度的str 
	for(int i=0;i<MAXNODE;i++){
		if(t[i].weight==0||t[i].data=='?'){
			continue;
		}else{
			int k=t[i].data-'a'+1;
			if(t[i].data=='#'){
				max=max>strlen(hc[0])?max:strlen(hc[0]);
				min=min<strlen(hc[0])?min:strlen(hc[0]);
			}else{
				max=max>strlen(hc[k])?max:strlen(hc[k]);
				min=min<strlen(hc[k])?min:strlen(hc[k]);
			}
		}
	} 
	
	int flag=0;
	printf("\t\t\t请输入要解密的字符串:");
	getchar();
	gets(ch);
	for(int j=0;j<strlen(ch);j++){
		if(ch[j]==''&&strlen(str)!=0){
			printf("\n解密失败,不存在此编码:%s\n",str);
			return ;
		}
//		else if(ch[j]==''&&flag==0){
//			printf("\n空文件,解密失败,请先输入内容\n");
//			return ;
//		}
		flag=1;			
		if(ch[j]=='0'){
			strcat(str,l);
			num++;
		}else if(ch[j]=='1'){
			strcat(str,r);
			num++;
		}else if(ch[j]=='\0'){
			printf("\n解密结束\n");
			return ;
		}else{
			printf("错误输入起始点%c",ch[j]);
			printf("\n解密失败,密文有误,仅含0与1的数字,重新检查密文\n");
			return ;
		}
		if(num>max){
			printf("解密失败,密文有误,存在未知编码且大于最长编码,重新检查密文\n");
			return ;
		}	
		//打印,将拼接的字符串依次与编码比较,若相同,则输出对应字符 
		for(int i=0;i<MAXNODE;i++){
			if(t[i].weight==0||t[i].data=='?'){
				continue;
			}else{
				int k=t[i].data-'a'+1;                             //空格情况特殊处理 
				if(t[i].data=='#'){
					if(!strcmp(str,hc[0])){
						printf(" ");
						memset(str,0,MAX);
						num=0; 
						break;
					}
					
				}else{
					if(!strcmp(str,hc[k])){                            //字符串与原有编码匹配成功后 
						printf("%c",'a'+k-1);
						memset(str,0,MAX);
						num=0; 
						break;
					}
				}			
		    }
		}
		

}
        printf("\n");
    	if(num!=0){
		printf("错误输入起始点:%s",str);
		printf("密文有误,不存在此种编码或小于最短编码,退出后重新输入\n");
		return ;
		}

//	printf("%d\n",num);
	printf("\n解析完成\n");
	return ;
}
//创建新Huffman树   效果类似于重载函数 
void newTree(HuffmanTree t){
	FILE *fp;
	int i=0,j;
	int w[MAX-1];
	char c[MAX-1];
	for(i=0;i<MAX;i++){
		w[i]=0;
		if(i==0){
			c[0]='#';
		}else{
			c[i]='a'+i-1;
		}
	}
	fp=fopen("data.txt","r");
	char ch;
//	printf("开始统计\n");
	while(!feof(fp)){	
		ch=fgetc(fp);
		if(ch==' '){
			w[0]++;
		}else if(ch>='a'&&ch<='z'){
			int k;
			k=ch-'a'+1;
			w[k]++;
		}else if(ch==''){
//			printf("文本读取结束\n");
		}else{
			printf("\n文件格式有误,存在%c字符\n",ch);
			printf("频率统计中断\n");
			printf("文本应只包含26个小写英文字符和空格,请重新确认文本\n");	
		}
	}
//	printf("统计完成\n"); 
	fclose(fp);
	printf("新数据读入成功\n");
	int k;
	for(i=0;i<MAX;i++){
		for(int j=0;j<MAX-1;j++){
			if(w[j]>w[j+1]){
				k=w[j];w[j]=w[j+1];w[j+1]=k;
				ch=c[j];c[j]=c[j+1];c[j+1]=ch;
			}
		}
	} 
//	printf("开始建树\n"); 
	int front,rear,num;
	for(i=0;i<MAX;i++){
		if(w[i]!=0){
			break;
		}
	} 
	front=i;
	num=MAX-i;
	for(j=0;j<(2*MAX-1);j++){
		if(j<front){
			t[j].data='?';t[j].weight=0;t[j].xb=j;
		}
		else if(j<front+num){
			t[j].data=c[j];t[j].weight=w[j];t[j].xb=j;
		}else{
			t[j].data='?';t[j].weight=0;t[j].xb=j;
		}
	}
	rear=MAX-1;
	Node p;
	int xb;
	p=t[MAXNODE+1];
	while(front!=rear){
		t[rear+1].data='?';
		t[rear+1].weight=t[front].weight+t[front+1].weight;
		rear=rear+1;
		for(i=rear;i>front+1;i--){
			if(t[i].weight<t[i-1].weight){
				t[i].xb--;t[i-1].xb++;
				p=t[i];t[i]=t[i-1];t[i-1]=p;
				continue;
			}
			xb=i;
			break;
		}
		t[front].parent=xb;t[front+1].parent=xb;
		t[xb].lchild=t[front].xb;
		t[xb].rchild=t[front+1].xb;
		front=front+2;		
	} 
	for(j=0;j<(MAXNODE);j++){
		if(t[j].weight==0){
			t[j].lchild=t[j].rchild=t[j].parent=-1;
		}
		if(t[j].data!='?'){
			t[j].lchild=t[j].rchild=-1;
		}
	} 
	t[rear].parent=-1;
	printf("新Huffman树创建成功\n");

	return ;
}

void menu(HuffmanTree t,HuffmanCode hc){
	int p;
	int i,j;
	printf("\n\t\t\t1.初始化数据\n");
	printf("\t\t\t2.加密\n");
	printf("\t\t\t3.解密\n");
	printf("\t\t\t4.txt文件加密\n");
	printf("\t\t\t5.txt文件解密\n");
	printf("\t\t\t6.退出\n");
	printf("\n\t\t\t功能选择:");
	scanf("%d",&p);
	switch(p){
		case 1:
			system("cls");
			creatHuffman(t);
			printf("\n");
			system("pause"); 
			break;
		case 2:
			system("cls");
			if(!creatCode(t,hc)){
				printf("空树,请先创建树\n");
				system("pause");
				break;
			}				
			enCode(hc);			
			system("pause"); 
			break;
		case 3:
			system("cls");
			if(!creatCode(t,hc)){
				printf("空树,请先创建树\n");
				system("pause");
				break;
			}
			deCode(t,hc);
			system("pause");
			break;
		case 4:
			system("cls");
			newTree(t);
			creatCode(t,hc);
			enCode(hc);
			system("pause");
			break;
		case 5:
			system("cls");
			newTree(t);
			creatCode(t,hc);
			deCode(t,hc);
			system("pause");
			break;
		case 6:
			exit(0);
			break;
		default:
			system("cls");
			printf("无效输入,重试\n");
			system("pause"); 
			break;
	}
}


int main(){
	HuffmanTree t;
	t=(HuffmanTree)malloc((MAXNODE+1)*sizeof(Node));
	HuffmanCode hc;
	hc=(HuffmanCode)malloc((MAX+1)*sizeof(char *));
	while(1){
		system("cls");
		menu(t,hc);
	}
	return 0;
}
  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值