哈夫曼编码

来源:互联网 发布: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
原创粉丝点击