哈夫曼编码
来源:互联网 发布:ubuntu 运行c 编辑:程序博客网 时间:2024/06/09 20:41
哈夫曼编码(还有对应的实验报告,在我的上传资源里,可以免费下载))
1.设计内容
1.添加用户登录密码
2.建立哈夫曼树:读入文件(*.souce),统计文件中字符出现的频度,并以这些字符的频度作为权值,建立哈夫曼树。
3.编码:利用已建立好的哈夫曼树,获得各个字符的哈夫曼编码,并对正文进行编码,然后输出编码结果,并存入文件(*.code)中。
4.译码:利用已建立好的哈夫曼树将文件(*.code)中的代码进行译码,并输出译码结果,并存入文件(*.decode)中。
2.各个模块详细的功能描述。
1.登录:输入初始密码登录进入菜单页面,三次输错密码后自动退出系统。
2.初始化源文件:通过键盘录入要进行压缩的内容,并将输入的内容保存到hfm.souce文件当中。
3.查询字符的编码:统计hfm.souce中不同字符出现的频度,赋予每个字符不同权重,根据权重建立哈夫曼树,然后输出每个字符对应的哈夫曼编码。
4.打印哈弗曼树:依次按照字符,权重,左子树,右子树,双亲打印哈夫曼树。
5.查询编码后文件:从hfm.souce中读出源文件内容,利用建立好的哈夫曼树将该内容进行编码,并保存到hfm.code文件中,输出编码后内容。
6.查询译码后文件:从hfm.code 文件中读出编码后内容,利用哈夫曼树进行译码,将译码后的文件保存到hfm.decode文件中,并输出译码后文件。
7.退出:退出系统
#include<stdio.h>#include<stdlib.h>#include<conio.h>#include<windows.h>#include <graphics.h>#pragma comment (lib,"Winmm.lib")#define N 26#define M 2*N-1#define MAX 10000#define MAXSIZE 100menu();typedef struct{char ch;int weight,rchild,lchild,parent;}hfm;typedef struct{ char bits[N]; //位串 int start; //编码在位串中的起始位置 char ch; //字符}codetype;typedef struct{ char ch; int weight; }weighttype;read_in_f1(weighttype weight[N]){int i,j,k=0,n=0,m;;char ch,cd[MAX];//cd[MAX]缓冲数组 FILE *fp; if((fp=fopen("hfm.souce","r"))==NULL) { printf("not open"); exit(0); } while ((ch=fgetc(fp))!=EOF)cd[n++]=ch;for(i=0;i<n;i++){m=0;if(cd[i]=='$') continue; weight[k].ch=cd[i];for(j=i;j<n;j++){if(cd[j]==weight[k].ch){m++;cd[j]='$';}}weight[k].weight=m;k++;} fclose(fp);}void create_hfm(hfm HFM[],weighttype weight[N]){char c;int i,j,f,p1,p2,s1,s2;//p1,p2为最小和次小节点的下标,s1,s2为最小和次小节点的权重for(i=0;i<M;i++){HFM[i].weight=0;HFM[i].rchild=-1;HFM[i].lchild=-1;HFM[i].parent=0;HFM[i].ch='^';}for(i=0;i<N;i++){if(weight[i].weight!=0){HFM[i].ch=weight[i].ch; HFM[i].weight=weight[i].weight;}}for(i=N;i<M;i++){p1=0;p2=0;s1=s2=MAX;for(j=0;j<i;j++){if(HFM[j].parent==0)if(HFM[j].weight<s1) //找权重最小的节点{s1=HFM[j].weight;p1=j;} else if(HFM[j].weight<s2) {s2=HFM[j].weight;p2=j; //找权重次小的节点}}HFM[i].weight=HFM[p1].weight+HFM[p2].weight; //赋新结点权重HFM[i].lchild=p1; HFM[i].rchild=p2; //赋新结点左右孩子指针HFM[p1].parent=i; HFM[p2].parent=i; //改变最小节点和次小节点的双亲指针}}void hfmcode(codetype code[],hfm HFM[])//根据哈夫曼树求出哈夫曼编码{int i,j,c,p; codetype cd; //缓冲变量char ch; FILE *fp1,*fp2; for(i=0;i<N;i++){cd.start=N; cd.ch=HFM[i].ch; c=i; //从叶结点出发向上回溯 p=HFM[i].parent; //HFM[p]是HFM[i]的双亲while(p!=0){cd.start--;if(HFM[p].lchild==c) cd.bits[cd.start]='0'; //HFM[i]是左子树,生成代码'0' else cd.bits[cd.start]='1'; //HFM[i]是右子树,生成代码'1'c=p; p=HFM[p].parent;}code[i]=cd; //第i+1个字符的编码存入code[i]}printf("输出每个字符的哈夫曼编码:\n");for(i=0;i<N;i++){if(HFM[i].weight!=0){printf("%c: ",code[i].ch);for(j=code[i].start;j<N;j++){printf("%c ",code[i].bits[j]);}printf("\n");}} if((fp1=fopen("hfm.souce","r"))==NULL) { printf("not open"); exit(0); }if((fp2=fopen("hfm.code","wt"))==NULL){printf("写文件出错!!按任意键退出。");getch();exit(0); } while ((ch=fgetc(fp1))!=EOF){ for(i=0;i<N;i++) {if(ch==code[i].ch){for(j=code[i].start;j<N;j++){fprintf(fp2, "%c",code[i].bits[j] ); //向所建文件写一字符串//printf("%c ",code[i].bits[j]); }} }}fprintf(fp2, "%d",2);printf("保存成功!!请按任意键继续。\n"); fclose(fp2); fclose(fp1);printf("按任意键返回主菜单!!!"); getch();menu();}void decode(hfm HFM[M]) //依次读入电文,根据哈夫曼树译码{int i,j=0,s,g=0;FILE *fp1,*fp2; char b[MAX]; i=M-1; //从根结点开始往下搜索if((fp1=fopen("hfm.code","r"))==NULL){printf("读文件出错!!按任意键退出。"); getch(); exit(0); }if((fp2=fopen("hfm.decode","wt"))==NULL){printf("xie文件出错!!按任意键退出。");getch(); exit(0); }while ((s=fgetc(fp1))!=EOF){b[g++]=s;} printf("译码后的字符为:\n"); while(b[j]!='2'){if(b[j]=='0')i=HFM[i].lchild; //走向左孩子 elsei=HFM[i].rchild; //走向右孩子if(HFM[i].lchild==-1) //tree[i]是叶结点{fprintf(fp2, "%c",HFM[i].ch);printf("%c",HFM[i].ch); i=M-1; //回到根结点}j++;}printf("保存成功!!请按任意键继续。\n");fclose(fp2);fclose(fp1);printf("按任意键返回主菜单!!!"); getch();menu();}save_in_f1()//创建文件{char ch;FILE *fp;if((fp=fopen("hfm.souce","wt"))==NULL){printf("写文件出错!!按任意键退出。");getch();exit(0);}printf("请输入原始文档(以^结束):\n");while(ch!='^'){ch=getchar();fputc(ch,fp); //向所建文件写一字符串 } printf("保存成功!!请按任意键继续。\n"); fclose(fp); printf("按任意键返回主菜单!!!"); getch();menu();}print(hfm HFM[MAX]){int i;printf("字符\t权重\t左子树\t右子树\t双亲\n"); for(i=1;i<M;i++){ //if(HFM[i].ch=='^') continue; printf("%c\t%d\t%d\t%d\t%d\n",HFM[i].ch,HFM[i].weight,HFM[i].lchild,HFM[i].rchild,HFM[i].parent);}printf("按任意键返回主菜单!!!"); getch();menu();}printcode(){FILE *fp;char ch;if((fp=fopen("hfm.code","r"))==NULL){printf("读文件出错!!按任意键退出。");getch();exit(0); } while ((ch=fgetc(fp))!=EOF){ if((ch-48)==2) break; printf("%d",ch-48);} fclose(fp);printf("按任意键返回主菜单!!!"); getch();menu();}menu(){system("cls"); system("color 03" ); puts(" "); puts(" ☆ hafuman编码☆ "); puts(" ═══════════════════════"); puts(" ╔═══════════════════════════════╗"); puts(" ║ ※1. 初始化源文件 ║"); puts(" ║ ║"); puts(" ║ ※2. 查询字符的编码 ║");puts(" ║ ║"); puts(" ║ ※3. 打印哈弗曼树 ║");puts(" ║ ║"); puts(" ║ ※4. 查询编码后文件 ║");puts(" ║ ║"); puts(" ║ ※5. 查询译码后文件 ║");puts(" ║ ║"); puts(" ║ ※6. 退出 ║"); puts(" ║ ║"); puts(" ╚═══════════════════════════════╝"); printf("\n\n请选择(1-6):");}void mi_ma()//密码验证{int i=0, x = 3; int flag = 0; char s[20];char mima[20]="123456"; system("cls"); system("color 03" );system("color 0a"); do { printf("\n\n"); printf(" ╒═━━━━━━╗\n"); printf(" ║请您输入密码: ║\n"); printf(" ╚━━━━━━━╝\n");for(i=0;i<6;i++){s[i]=getch(); printf("%c",s[i]); printf("\b*");}getch(); s[6]='\0'; printf("\n");if(!strcmp(s,mima))//进行密码验证 { printf("密码正确!!!!\n\n\n按任意键继续~~~\n");getch(); flag=1; break; } else { printf("密码错误,请重新输入:\n"); x--; } } while(x>0); if(!flag) { printf("你已经输入三次错误密码!"); exit(0); }}main(){int i;weighttype weight[N]={0};hfm HFM[MAX];codetype code[N]; //存放哈弗曼编码mi_ma();menu();while(1){loop:fflush(stdin);scanf("%d",&i); switch(i){ case 1: save_in_f1();read_in_f1(weight); //获取各个字符的出现的频率 create_hfm(HFM,weight);//建立哈弗曼树 break; case 2: read_in_f1(weight); //获取各个字符的出现的频率 create_hfm(HFM,weight);//建立哈弗曼树 hfmcode(code,HFM);//编码 break; case 3:/// read_in_f1(weight); //获取各个字符的出现的频率 //create_hfm(HFM,weight);//建立哈弗曼树print(HFM);//输出哈弗曼树break; case 5: read_in_f1(weight); //获取各个字符的出现的频率 create_hfm(HFM,weight);//建立哈弗曼树decode(HFM);//解码 break; case 4: read_in_f1(weight); //获取各个字符的出现的频率 create_hfm(HFM,weight);//建立哈弗曼树 printcode();break; case 6: exit(0);break; default:printf("您输入的编码不对!请重新输入:\a"); goto loop;}}}
0 0
- 信源编码---哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- CN和CNTK的介绍(一)
- 写一个Tomcat+Okhttp实现的聊天websocket聊天框架(二)--完成私聊功能
- leetcode 44. Wildcard Matching
- xampp下mysql解决中文乱码问题
- cas4.2.7定制登录页面样式(并且让页面默认使用中文提示)
- 哈夫曼编码
- 简单排序算法时间空间复杂度分析及应用(1)-冒泡排序
- 线程安全
- c++指针的一些陷阱(更新ing)
- thinkphp部署到Linux后验证码功能不显示
- 类和对象的深入剖析【整理】
- 神经网络向量化实现
- Protobuffer 中文序列化反序列化乱码?丢失?
- 200. Number of Islands(unsolved)