# include <stdio.h> # include <stdlib.h> # include <string.h> # include <limits.h> # include <fstream> # include <iostream> using namespace std; # define maxsize 100 //将信息转化为哈夫曼码 //康玉健 //17041114 typedef struct { int order;//序号 char letter;//字母 int count;//出现的次数 }LET;//字母 typedef struct { int weight; int parent; int left_child; int right_child; char elem; }HTNode,*HuffmanTree;//定义哈弗曼树 typedef struct { char letter; char *code; }CODE;//哈夫曼表 typedef char**HuffmanCode; void creat_HuffmanTree(HuffmanTree &HT,int n,LET *letter);//创建哈弗曼树 void HuffmanTree_select(HuffmanTree &HT,int num_node,int &s1,int &s2);//进行选择 LET* statis_letter(char *data);//统计字母个数 int statis_letternum(LET* letter);//统计含有字符多少个 //LET *outcome(LET*letters);//返回最终的数组 void Huffman_code(HuffmanTree &HT,HuffmanCode &HC,int n);//创建哈夫曼编码表 void print_HuffmanCode(HuffmanCode &HC,LET *letter,int n);//打印哈夫曼表 char* output_HuffmanCode(HuffmanCode &HC,char *data,int n,LET*letter);//输出哈夫曼编码 //void resolve_HuffmanCode(HuffmanTree &HT,HuffmanCode HC,char *code)//解哈夫曼编码 int Root_Tree(HuffmanTree &HT,int n); //得到哈夫曼树的根 void resolve_HuffmanCode(HuffmanTree &HT,LET*letter2,char *code,int n); LET* enter_weight(int len,LET* letter);//输入权值 void output_huffman_to_file(HuffmanTree &HT,int len);//将哈夫曼树输入到文件中 void Init(int len,LET* letter);//初始化功能 HuffmanTree En_code(int len,LET* letter);//编码到一个文件中 void De_code(HuffmanTree &HT,LET*letter2,char *code,int n);//译码部分 void print_code(void); void print_Tree(HuffmanTree &HT,int len); int main(void) { int flag=0; int returnmenu; int choice; printf("****************************************\n"); printf("* 哈夫曼编码器 *\n"); printf("* 版本1.0 *\n"); printf("* *\n"); printf("* *\n"); printf("* *\n"); printf("* *\n"); system("pause"); system("cls"); HuffmanTree HT=NULL; char data[maxsize]; char code[maxsize]; printf("请输入一个您要进行编码的字符串:(长度小于100)\n"); gets(data); LET*letter=statis_letter(data);//统计字符串中各个字母出现的频率 int len=statis_letternum(letter); LET*letter2= enter_weight(len,letter); do{ system("cls"); printf("* 【1】初始化 *\n"); printf("* 【2】编码 *\n"); printf("* 【3】译码 *\n"); printf("* 【4】印代码文件 *\n"); printf("* 【5】打印哈夫曼树 *\n"); printf("请输入您的选择:\n"); scanf("%d",&choice); if(choice==1) { Init(len,letter2); } else if(choice==2) { HT=En_code(len,letter2); } else if(choice==3) { FILE* fp=fopen("编完码的结果.txt","r"); if(fp==NULL) { printf("文件打不开!\n"); } else { fscanf(fp,"%s",&code); fclose(fp); De_code(HT,letter2,code,len); } } else if(choice==4) { print_code(); } else if(choice==5) { print_Tree(HT,len); } else { printf("输入错误!\n"); } printf("是否返回主菜单:\n"); printf("【1】是,【2】否\n"); scanf("%d",&returnmenu); } while(returnmenu==1); } void creat_HuffmanTree(HuffmanTree &HT,int n,LET*letters)//创建哈夫曼树 { int m; int i; int j; int s1,s2; if(n<=1) return ; m=2*n-1; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); HT[0].elem='#'; HT[0].left_child=0; HT[0].right_child=0; HT[0].parent=0; HT[0].weight=0; for(i=1;i<=m;i++) { HT[i].elem='#'; HT[i].parent=0; HT[i].left_child=0; HT[i].right_child=0; } //依次输入%d个节点的位权值 for(i=1;i<=n;i++) { HT[i].weight=letters[i-1].count; HT[i].elem=letters[i-1].letter; } //从1-i-1选择最小的两个节点并将权值返回给s1。s2 for(i=n+1;i<=m;i++) { HuffmanTree_select(HT,i-1,s1,s2); HT[s1].parent=i; HT[s2].parent=i; HT[i].left_child=s1; HT[i].right_child=s2; HT[i].weight=HT[s1].weight+HT[s2].weight; } } void HuffmanTree_select(HuffmanTree &HT,int num_node,int &s1,int &s2)//选择最小权值的下标 { int i; s1 = s2 = 0; int min1 = INT_MAX;//最小值,INT_MAX在<limits.h>中定义的 int min2 = INT_MAX;//次小值 for ( i = 1; i <=num_node; ++i ) { if ( HT[i].parent == 0 ) {//筛选没有父节点的最小和次小权值下标 if ( HT[i].weight < min1 ) {//如果比最小值小 min2 = min1; s2 = s1; min1 = HT[i].weight; s1 = i; } else if ( (HT[i].weight >= min1) && (HT[i].weight < min2) ) {//如果大于等于最小值,且小于次小值 min2 = HT[i].weight; s2 = i; } else {//如果大于次小值,则什么都不做 ; } } } } LET* statis_letter(char *data)// 统计多少字符串之中各个字母数目 { int i,j; int len; int count=0; LET* letter=(LET*)malloc(26*sizeof(LET)); for(i=0;i<26;i++)//依次把26个字母放到字母结构体数组之中 { letter[i].order=i; letter[i].letter='A'+i; letter[i].count=0; } for(i=0;i<strlen(data);i++) { for(j=0;j<26;j++) { if(letter[j].letter==data[i]) { letter[j].count++; } } } return letter; } int statis_letternum(LET* letter)//统计字母的个数 { int i; int count=0; for(i=0;i<26;i++) { if(letter[i].count!=0) { count++; } } return count; } /*LET *outcome(LET*letters)//把所有返回一个有全部字母的数组 { int i; int counts=0; int len=statis_letternum(letters); LET *outcome=(LET*)malloc(len*sizeof(LET)); for(i=0;i<26;i++) { if (letters[i].count!=0) { outcome[counts].letter=letters[i].letter; outcome[counts].order=letters[i].count; outcome[counts].order=letters[i].order; counts++; } } printf("count=%d",counts); return outcome; }*/ void Huffman_code(HuffmanTree &HT,HuffmanCode &HC, int n)//哈夫曼编码树 { int i; int c; int start; int f; HC=(HuffmanCode)malloc((n+1)*sizeof(char *)); char *cd=(char*)malloc(n*sizeof(char)); cd[n-1]='\0'; for(i=1;i<=n;++i) { start=n-1; c=i; f=HT[i].parent; while(f!=0) { --start; if(HT[f].left_child==c) { cd[start]='0'; } else { cd[start]='1'; } c=f; f=HT[f].parent; HC[i]=(char*)malloc((n-start)*sizeof(char)); strcpy(HC[i],&cd[start]); } } free(cd); } void print_HuffmanCode(HuffmanCode &HC,LET *letter,int n) { FILE* fp=fopen("编码表.txt","w"); if(fp==NULL) { printf("文件打不开呀!兄弟!\n"); } else { int i; for(i=0;i<n;i++) { if(letter[i].count!=0) { fprintf(fp,"字母:"); fprintf(fp,"%c ",letter[i].letter); fprintf(fp,"权值:"); fprintf(fp,"%d ",letter[i].count); fprintf(fp,"哈夫曼编码为:\n"); fprintf(fp,"%s",HC[i+1]); fprintf(fp,"\n"); } } fclose(fp); } } char * output_HuffmanCode(HuffmanCode &HC,char *data,int n,LET* letter) { int i,j; CODE *HCode=(CODE*)malloc(n*sizeof(CODE)); char *output_string=(char*)malloc(maxsize*sizeof(char)); output_string[0]='\0'; for(i=0;i<n;i++) { HCode[i].letter=letter[i].letter; } for(i=0;i<n;i++) { HCode[i].code=(char*)malloc(strlen(HC[i+1])*sizeof(char)); strcpy(HCode[i].code,HC[i+1]); } printf("转化为哈夫曼码为:\n"); for(i=0;i<strlen(data);i++) { for(j=0;j<n;j++) { if(data[i]==HCode[j].letter) { strcat(output_string,HCode[j].code); printf("%s",HCode[j].code); } } } printf("\n"); printf("传输的哈夫曼编码为:\n"); puts(output_string); FILE* fp=fopen("编完码的结果.txt","w"); if(fp==NULL) { printf("读取文件失败!\n"); } else { for(i=0;i<strlen(output_string);i++) { if(i+1%50==0) { fprintf(fp,"\n"); } fprintf(fp,"%c",output_string[i]); } } fclose(fp); return output_string; } int Root_Tree(HuffmanTree &HT,int n) //返回哈弗曼树根节点的下标 { int i; int m=2*n-1; for(i=1;i<=m;i++) { if(HT[i].parent==0) { break; } } return i; } void resolve_HuffmanCode(HuffmanTree &HT,LET*letter2,char *code,int n) { FILE* fp=fopen("译码的结果.txt","w"); if(fp==NULL) { printf("文件打不开,我的朋友!\n"); } else { int root=Root_Tree(HT,n); int i=root; int weight; do { if(*code=='0')//如果 { i=HT[i].left_child; } else if(*code=='1') { i=HT[i].right_child; } if(HT[i].left_child==0&&HT[i].right_child==0)//如果到达了叶子节点回到根节点 { weight=HT[i].weight; fprintf(fp,"%c",HT[i].elem); i=root; } code++; } while(*code!='\0'); fclose(fp); } } LET* enter_weight(int len,LET* letter) { int i; int count=0; int weight; LET*letter2=(LET*)malloc(len*sizeof(LET)); for(i=0;i<26;i++) { if(letter[i].count!=0) { printf("请输入%c的权值:\n",letter[i].letter); scanf("%d",&weight); letter2[count].count=weight; letter2[count].order=letter[i].order; letter2[count].letter=letter[i].letter; count++; } } return letter2; } void Init(int len,LET* letter) { int i; int count=0; char data[maxsize]; HuffmanCode HC=NULL; HuffmanTree HT=NULL; char code[100]; creat_HuffmanTree(HT,len,letter); output_huffman_to_file(HT,len); } void output_huffman_to_file(HuffmanTree &HT,int len)//打印哈夫曼树 { char code[100]; ofstream file; file.open("哈夫曼树.txt"); for(int i=0;i<2*len;i++) { //file<<i<<" "; file<<HT[i].elem<<" "; file<<HT[i].weight<<" "; file<<HT[i].parent<<" "; file<<HT[i].left_child<<" "; file<<HT[i].right_child<<" "; file<<endl; } file.close(); } HuffmanTree En_code(int len,LET* letter)//读取哈夫曼树并对其进行编码 { //创建哈夫曼树 HuffmanTree HT_new=(HuffmanTree)malloc(2*len*sizeof(HTNode)); //创建一个新的哈夫曼树 //从文件中读取哈夫曼树 char ch1,ch2; char elem; int weight; int parent; int left_child; int right_child; char code[100]; HuffmanCode HC; FILE *fp=fopen("哈夫曼树.txt","r"); for(int i=0;i<2*len;i++) { fscanf(fp,"%c",&elem); fscanf(fp,"%d",&weight); fscanf(fp,"%d",&parent); fscanf(fp,"%d",&left_child); fscanf(fp,"%d",&right_child); fscanf(fp,"%c%c",&ch1,&ch2); HT_new[i].elem=elem; HT_new[i].weight=weight; HT_new[i].parent=parent; HT_new[i].left_child=left_child; HT_new[i].right_child=right_child; } //file.close(); fclose(fp); for(int i=0;i<2*len;i++) { cout<<HT_new[i].elem<<" "; cout<<HT_new[i].weight<<" "; cout<<HT_new[i].parent<<" "; cout<<HT_new[i].left_child<<" "; cout<<HT_new[i].right_child<<endl; } //打开要被编码的文件 FILE *fp1=fopen("要被编码的数据.txt","r"); fscanf(fp1,"%s",&code); fclose(fp1); Huffman_code(HT_new,HC,len); output_HuffmanCode(HC,code,len,letter); //打印哈夫曼树编码表 print_HuffmanCode(HC,letter,len); return HT_new; } void De_code(HuffmanTree &HT,LET*letter2,char *code,int n) { resolve_HuffmanCode(HT,letter2,code,n); } void print_code(void) { char code[maxsize]; FILE* fp=fopen("译码的结果.txt","r"); if(fp==NULL) { printf("打不开文件啊,兄弟!\n"); exit(-1); } else { fscanf(fp,"%s",&code); fclose(fp); } printf("译码的结果为:\n"); puts(code); } void print_Tree(HuffmanTree &HT,int len) { FILE* fp=fopen("打印哈夫曼树.txt","w"); if(fp==NULL) { printf("文件打不开!\n"); exit(-1); } else { for(int i=0;i<2*len;i++) { fprintf(fp,"序号: "); fprintf(fp,"元素: "); fprintf(fp,"权值: "); fprintf(fp,"父母: "); fprintf(fp,"左孩子: "); fprintf(fp,"右孩子: "); fprintf(fp,"\n"); fprintf(fp,"%d ",i); fprintf(fp,"%c ",HT[i].elem); fprintf(fp,"%d ",HT[i].weight); fprintf(fp,"%d ",HT[i].parent); fprintf(fp,"%d ",HT[i].left_child); fprintf(fp,"%d ",HT[i].right_child); fprintf(fp,"\n"); } fclose(fp); } }