【题目描述】
给定一篇用于通信的英文电文,统计该电文中每个字符出现的频率,按频率左小右大的方法为这些字符建立哈夫曼(Huffamn)树,并编出每个字符的哈夫曼树码,输出该电文的哈夫曼码译文。
【输入】
输入文件huffman.in是一篇用于通信的英文电文。
【输出】
输出文件huffman.out输出该电文的哈夫曼码译文。
【输入输出样例1】
huffman.in | huffman.out |
aaccdddbacbcddddddd | 011011000011101001100010001111111 |
【数据限制】
2<=英文电文字符数<=10000000
统计以上abcd出现的个数。
a:3 b:2 c:4 d:10
构造出哈夫曼树
a:011 b:010 c :00 d:1
二、译码
【题目描述】
给定2个输入文件,第1个输入文件是用于通信的英文电文,统计该电文中每个字符出现的频率,按频率左小右大的方法为这些字符建立哈夫曼(Huffamn)树,并编出每个字符的哈夫曼树码;第2个输入文件是已经按第1个输入文件的英文电文编好的哈夫曼码,输出该哈夫曼码的对应的英文电文。
【输入】
第1个输入文件为huffman.in是用于通信的英文电文, 第2个输入文件codeToTxt.in是已经按第1个输入文件编好的哈夫曼码。
【输出】
输出文件codeToTxt.out输出codeToTxt.in文件内容的英文电文。
【输入输出样例1】
huffman.in | codeToTxt.in | codeToTxt.out |
aaccdddbacbcddddddd | 011111011000011101001100010001111 | adddaccdddbacbcdddd |
【数据限制】
2<=英文电文字符数<=10000000
- #include<stdio.h>
- #include<stdlib.h>
- #include<string.h>
- #include<conio.h>
- #define MAXNUM 60
- typedef struct
- {
- char ch;
- int weight; //权值,这个字符出现的频率
- int parent;
- int left;
- int right;
- }HuffNode;
- typedef struct
- {
- char code[MAXNUM];
- int start;
- }HuffCode;
- HuffNode ht[MAXNUM*2]; //存放哈夫曼树
- HuffCode hcd[MAXNUM]; //存放ht数组中对应的字符的编码
- int n; //字符的个数
- //初始化哈夫曼树ht
- void initHt()
- {
- FILE * fp;
- char ch;
- int i=0;
- //从文件document/character.txt中读出要编码的字符和权值
- if((fp=fopen("document/character.txt","r"))==NULL){
- printf("can not open the file character.txt");
- exit(0);
- }
- ht[i].left=ht[i].right=ht[i].parent=-1;
- while((ch=fgetc(fp))!=EOF){
- if(ch=='\n'){
- i++;
- ht[i].left=ht[i].right=ht[i].parent=-1;
- }
- else if((ch>='a' && ch<='z')||(ch>='A' && ch<='Z'))
- ht[i].ch=ch;
- else if(ch>='0'&&ch<='9')
- ht[i].weight=ht[i].weight*10+ch-'0';
- }
- n=i+1;
- if(fclose(fp)){
- printf("can not close the file character.txt");
- exit(0);
- }
- }
- //构造哈夫曼树,看成有n棵树,选择权值最小的两棵树合并
- void createHuffTree()
- {
- int i=0,k;
- int minI,minJ;
- int f=0;
- minI=minJ=-1; //minI<minJ
- for(k=n;k<2*n-1;k++){
- //寻找ht中权值最小且无父结点的两个结点
- i=0;
- f=0;
- while(ht[i].ch!='\0'){
- if(ht[i].parent==-1){
- if(f==0){
- minI=i;
- f++;
- }else if(f==1){
- if(ht[i].weight<ht[minI].weight){
- minJ=minI;
- minI=i;
- }else
- minJ=i;
- f++;
- }else{
- if(ht[i].weight<ht[minI].weight){
- minJ=minI;
- minI=i;
- }else if(ht[i].weight<ht[minJ].weight)
- minJ=i;
- }
- }
- i++;
- }
- //合并两个结点
- ht[k].ch='#';
- ht[k].left=minI;
- ht[k].right=minJ;
- ht[k].weight=ht[minI].weight+ht[minJ].weight;
- ht[k].parent=-1;
- ht[minI].parent=ht[minJ].parent=k;
- }
- }
- //将一个字符串反转
- void reverse(char *str)
- {
- int i,j;
- char ch;
- for(i=0,j=strlen(str)-1;i<j;i++,j--){
- ch=str[i];
- str[i]=str[j];
- str[j]=ch;
- }
- }
- //哈夫曼编码,通过父节点从下往上找
- void createHuffCode()
- {
- int i,j,length;
- FILE * fp;
- for(i=0;i<n;i++){
- length=0;
- j=i;
- //给每个字符进行编码
- while(ht[j].parent!=-1){
- if(ht[ht[j].parent].left==j){
- hcd[i].code[length++]=0+'0';
- }else
- hcd[i].code[length++]=1+'0';
- j=ht[j].parent;
- }
- hcd[i].start=hcd[i].code[length-1]-'0';
- hcd[i].code[length]='\0';
- reverse(hcd[i].code);
- }
- //把hcd字符编码写入文件document/code.txt中
- if((fp=fopen("document/code.txt","w"))==NULL){
- printf("can not open the file character.txt");
- exit(0);
- }
- for(i=0;i<n;i++){
- fputc(ht[i].ch,fp);
- fputs(" ",fp);
- fputs(hcd[i].code,fp);
- fputc('\n',fp);
- }
- if(fclose(fp)){
- printf("can not close the file character.txt");
- exit(0);
- }
- }
- //哈夫曼解码,每次都从根节点开始搜索
- int releaseHuffCode(char *str,char* code)
- {
- int root=2*n-2;
- int length=0,i=0;
- while(code[i]){
- if(code[i]=='0'+0)
- root=ht[root].left;
- else if(code[i]=='0'+1)
- root=ht[root].right;
- else
- return 0;
- if(ht[root].left==-1 && ht[root].right==-1){
- str[length++]=ht[root].ch;
- root=2*n-2;
- }
- i++;
- }
- str[length]='\0';
- if(root==2*n-2)
- return 1;
- return 0;
- }
- //用户输入编码字符
- void encode()
- {
- int i=0,j,f=1;
- char str[50];
- char code[500]={'\0'};
- printf("\n请输入要编码的字符串(length<50)\n");
- scanf("%s",str);
- while(str[i]){
- if((str[i]>='a'&&str[i]<='z')||(str[i]>='A'&&str[i]<='Z')){
- for(j=0;j<n;j++)
- if(str[i]==ht[j].ch){
- strcat(code,hcd[j].code);
- break;
- }
- i++;
- }else{
- f=0;
- break;
- }
- }
- if(f)
- puts(code);
- else
- printf("你输入的字符串错误!\n");
- printf("按任意键后重新选择!\n");
- getch();
- }
- //用户输入解码字串
- void decode()
- {
- char str[50];
- char code[500];
- printf("\n请输入要解码的字串(用0和1表示)\n");
- scanf("%s",code);
- if(releaseHuffCode(str,code))
- puts(str);
- else
- printf("你输入的字串错误!\n");
- printf("按任意键后重新选择!\n");
- getch();
- }
- //主函数
- void main()
- {
- int choice=1;
- initHt();
- createHuffTree();
- createHuffCode();
- while(choice){
- system("cls");
- printf("/****************哈夫曼编码与解码*********************/\n");
- printf(" 在document/character.txt 文件中存放着各个字母的权值\n");
- printf(" 程序从中读出各个字母的权值构造哈夫曼树并进行编码\n");
- printf(" 各个字符的编码存在document/code.txt文件中\n");
- printf("/*****************************************************/\n");
- printf("\n请输入你的选择:1 ---- 编码 2 ---- 解码 0 ---- 退出\n");
- scanf("%d",&choice);
- switch(choice){
- case 1:
- encode();
- break;
- case 2:
- decode();
- break;
- case 0:
- printf("谢谢使用!\n");
- break;
- default:
- choice=1;
- printf("你的输入错误!按任意键后重新输入!\n");
- getch();
- break;
- }
- }
- }