题目:
试编写一个Huffman编码系统,用于数据加密和解密。该系统应具有以下功能:
链接: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;
}