哈夫曼编码解码课程设计源代码

      数据结构课程设计

“哈夫曼编码/译码器
设计一个利用哈夫曼算法的编码和译码系统,重复显示并处理以下项目,知道选择退出为止/
【基本要求】
1)将权值数据存放在数据文件(文件名data.txt 位于执行程序的当前目录中)
2)分别采用动态和静态存储结构
3)初始化:键盘上输入字符集大小n,n个字符和n个权值,建立哈夫曼树
4)编码:利用建好的哈夫曼树生成哈夫曼编码
5)输出编码
6)实现译码功能:即随机输入一组字符,实现编码,并能够根据编号的码翻译成输入的字符。

 

运行界面如下所示:

 

 

具体参考另一篇博客:https://mp.csdn.net/postedit/85055367

源码

/*****************************  哈夫曼编码译码器**********************************************/ 
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
#include<windows.h>
//#include <graphics.h>
   //哈夫曼树结点的结构
typedef struct{
    char ch;
    int weight;
    int parent,lchild,rchild;
}HTNode, * HuffmanTree;   //动态分配数组存储哈夫曼树

typedef char **HuffmanCode;    //动态分配叔叔存储哈夫曼编码表

//   显示菜单
void Menu();
void color(int x);
void gotoxy(int a,int b);
void HuffmanCoding(HuffmanTree &HT, char *charcater,int* w,int n);//建立哈夫曼树
void select(HuffmanTree HT,int j,int *x,int *y);  //从建好的树中选两个最小的结点
void Init();  //初始化哈夫曼
void Coding();// 文件编码
void Decoding();// 文件译码
void Print_tree(); //打印哈夫曼树 
void printfht(int root,int height);
int Read_tree(HuffmanTree &x);//从文件中读入哈夫曼树
void  Decode(HuffmanTree &,char *ToBeTran, int n);
void  Encode(HuffmanTree &,HuffmanCode,int);
HuffmanTree HT;    //全局变量
int n = 0;    //全局变量,存放哈夫曼树叶子结点的数目 
int Decodeflag=0;

void first(){   //登陆界面
    color(2); 
    gotoxy(35,8); 
   printf("哈夫曼编码/译码器3.0");
     color(3);
   gotoxy(38,14);
   printf("制作人:组长   组员     组员"); 
    
} 
//自定义函根据参数改变颜色 
void color(int x)    
{
    if(x>=0 && x<=15)//参数在0-15的范围颜色
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);    //只有一个参数,改变字体颜色 
    else//默认的颜色白色
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}

/************调用函数设置光标位置 ***************/
void gotoxy(int a,int b){
    int xx = 0x0b;
    HANDLE hOutput;
    COORD loc;
    loc.X = a;
    loc.Y = b;
    hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出的句柄 
    SetConsoleCursorPosition(hOutput, loc);//设置光标位置 
    return;
}
void head()//标题显示
{   color(10);
   // gotoxy(20,20);
    printf("\t\t\t***********************************************\n");
    printf("\t\t\t***********************************************\n");
    printf("\t\t\t         欢迎使用哈夫曼编码/译码器\n");
    printf("\t\t\t************************************************\n");
    printf("\t\t\t************************************************\n");
}
/*********************设置人员滚动字幕****************************/
void gun(){
    {   
        char str[] = "制作人:AAA  BBB  CCC";//16 
        int i = 0,j = 0,k = 0,len = 0;
        len = strlen(str);
        for(i = 0; i < len;i++)
        {
            k++;
            Sleep(200);
            printf("%c",str[i]);
            if(i == len-1)
            {
                Sleep(200);
                for(j = 0; j < strlen(str); j++)
                    printf("\b");
                for(j=0;j<strlen(str);j++)
                {
                    putchar(' ');
                }
                i = -1;
            }
            if( k == 79)
            {
                for(j = 0; j < strlen(str); j++)
                    printf("\b");
                for(j=0;j<strlen(str);j++)
                {
                    putchar(' ');
                }
                printf("\r");
                k = 0;
                i=-1;
            }
        }    
    }
}

/********************************操作选择界面*********************************/
void Menu()  
{   
       head();
       color(12);
       printf("本系统操作功能如下:\n"); 
       printf(" \t\t-----------------------------------------------------\n");
       printf(" \t\t--                  请选择操作                    --\n");
       printf(" \t\t-----------------------------------------------------\n");
       printf("                                                      \n");
       printf(" \t\t*1---------------初始化赫夫曼树  ---------------\n");
       printf(" \t\t*2---------------文件编码        ---------------\n");
       printf(" \t\t*3---------------文件译码       ---------------\n");
       printf(" \t\t*4---------------打印树       ---------------\n");
       printf(" \t\t*0---------------退出            ---------------\n");
       printf(" -----------------------------------------------------\n");
       printf("请选择你要进行的操作:\n");
}
int main()
{
    char select;
    first();
    getch();
    system("cls");
      head(); 
       gotoxy(25,25);
       printf("请点击任意键继续使用。。。");
       getch();
       system("cls");  
    while (1)
    {   
        Menu();
        scanf("%c", &select);
        switch (select)  //选择操作,根据不同的序号选择不同的操作
        {     
            case '1':
                 system("cls"); 
                 Init();//初始化哈夫曼树 
                 break;
            case '2':
                   printf("请往文本中输入要编码的字符串!(编码根据文本XX的哈夫曼树!)\n");
                 system("cmd /c start 要编码的文件.txt");
                Coding();
                system("cmd /c start 编码完的文件.txt");
                break;
            case '3':
                printf("请往文本中输入要译码的字码!(译码编码完的文件)\n");
                system("cmd /c start 编码完的文件.txt");
                Decoding();
                system("cmd /c start 译码完的文件.txt");
                break;
            case '4':
                Print_tree();
                getch();
                system("cls");
                break;
            case '0':
                system("cls");    
                color(13);
                gotoxy(25,25);
                printf("欢迎下次使用,再见!!!!!!");
                exit(1);
             
            default:
            printf("Input error!(输入数字有误,请重新输入))\n");  
         }
         getchar();
    }
    return 0;
}
//建立一个输入条纹的函数
void printLine()
{
    printf("\n---------------------------------------\n");
} 
//初始化函数,输入n个字符及其对应的权值,根据权值建立哈夫曼树,并将其存于文件hfmtree中
void Init()
{
        FILE *fp;
        int i, n, w[256];    //数组存放字符的权值
        char character[256];    //存放n个字符
        system("cls");
        head();
        printf("\n输入字符个数:");
        scanf("%d", &n);        //输入字符集大小
        printf("请您按提示输入每种字符以及其对应的权值:\n");
        printLine(); 
        getch();
        for (i = 0; i<n; i++)
        {
           char b = getchar();
           printf("请您输入第%d个字符:\n",i+1);
           scanf("%c", &character[i]);
           printf("请输入该字符对应的权值:\n");
           scanf("%d", &w[i]);          //输入n个字符和对应的权值
           printLine(); 
        }
        printf("\n\n字符集为:\n");
        for(int i=0;i<n;i++)
        {
            printf("%c:\t%d\n",character[i],w[i]);   //将字符和权值打印出来 
        }
        HuffmanCoding(HT, character, w, n);    //建立赫夫曼树
        printf("下面将输入的字符的哈夫曼编码写入文件hfmtree.txt文件中\n"); 
        if ((fp = fopen("hfmtree.txt", "w")) == NULL)
            printf("Open file hfmtree.txt error!(打开hfmtree.txt文件错误)\n");
        //  fprintf(fp, "%s\t\t%s\t\t%s\t\t%s\t\t%s\t\t%s\n", "单元号", "字符", "权值", "双亲", "左孩子", "右孩子");
        for (i = 1; i <= 2 * n - 1; i++)
        {
            fprintf(fp, "%d %c %d %d %d %d\n", i, HT[i].ch, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
            //将建立的赫夫曼树存入文件hfmtree.txt中
        }
        printf("\n赫夫曼树建立成功,并已存于文件hfmtree.txt中\n");
        fclose(fp);
        gotoxy(60,40);
        printf("请点击任意键继续...");
        getch();
        system("cls");
        //Menu();
        
        Decodeflag=1;
        char *ToBeTran;
        HuffmanCode HC;
        char  ch;
        //while(scanf("%c",&ch)!=EOF)
        // getch(); 
        color(8);
        printf("点击回车查看字符集编码结果:\n"); 
        getch(); 
      //  select2=getchar();    //判断是否进行编码/解码测试 
        while(1) 
         {
            scanf("%c",&ch);
            if(ch!='*')       //输入*号跳出测试循环 
            {
               Encode(HT,HC,n);           //调用编码函数 
               Decode(HT,ToBeTran,n);       //调用解码函数 
            }
            else
              break;
              //Menu();
        
        }
        printf("\n");
        printf("\n");
        printf("\n");
}
//构造哈夫曼树的算法
void HuffmanCoding(HuffmanTree &HT, char *character, int * w, int n)
{  //w存放n个字符的权值(均>0),构造哈夫曼树HT
        int m, i, x, y;
        HuffmanTree p;
        if (n <= 1) return;
        m = 2 * n - 1;
        HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
        for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++character, ++w)
        {
             p->ch = *character;
           p->weight = *w;
           p->parent = 0; 
           p->lchild = 0; 
           p->rchild = 0;
        }
        for (; i <= m; ++i, ++p) 
        {
           p->ch = 0; 
           p->weight = 0;
           p->parent = 0;
           p->lchild = 0;
           p->rchild = 0; 
        }
        for (i = n + 1; i <= m; ++i)
        {
           select(HT, i - 1, &x, &y);
           HT[x].parent = i;
           HT[y].parent = i;
           HT[i].lchild = x; 
           HT[i].rchild = y;
           HT[i].weight = HT[x].weight + HT[y].weight;
        }
}
//从HT[1]到HT[j]中选择parent为0,weight最小的两个结点,用x和y返回其序号
void select(HuffmanTree HT, int j, int *x, int *y)
{
        int i;
        //int minwight=65535;
        //查找weight最小的结点
        for (i = 1; i <= j; i++)
             if (HT[i].parent == 0)
             {
                 *x = i; break;
             }
        for (; i <= j; i++)
            if ((HT[i].parent == 0) && (HT[i].weight<HT[*x].weight))
                *x = i;
        HT[*x].parent = 1;
        //查找weight次小的结点
        for (i = 1; i <= j; i++)
            if (HT[i].parent == 0)
            {
               *y = i; break;
             }
        for (; i <= j; i++)
            if ((HT[i].parent == 0) && (i != *x) && (HT[i].weight<HT[*y].weight))
              *y = i;
    /**     for(i=1;i<=j;i++)
         {
               if(HT[i].parent == 0&&HT[i].weight<minweight)
               {
                  *x=i;
                 minweight=HT[i].weigh;
              }
         }
         HT[*x].parent = 1;    
         for(i=1;i<=j;i++)
         {
               if(HT[i].parent == 0&&HT[i].weight<minweight)
               {
                  *y=i;
                 minweight=HT[i].weigh;
              }
         }
        HT[*y].parent = 1;    **/
}
//对文件正文进行编码,然后将结果存入另一个文件中
void Coding()
{
        FILE *fp, *fw;
        int i, f, c, start,r;
        char *cd;
        HuffmanCode HC;
        n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数
        //求赫夫曼树中各叶子节点的字符对应的的编码,并存于HC指向的空间中
        {
            HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
            cd = (char *)malloc(n * sizeof(char));
            cd[n - 1] = '\0';
            for (i = 1; i <= n; ++i)
            {
                start = n - 1;
                for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
                if (HT[f].lchild == c)
                   cd[--start] = '0';
                else 
                   cd[--start] = '1';
                HC[i] = (char *)malloc((n - start) * sizeof(char));
                strcpy(HC[i], &cd[start]);
            }
            free(cd);
        }
        if ((fp = fopen("要编码的文件.txt", "r")) == NULL)
           printf("Open file 要编码的文件.txt error!\n");
        if ((fw = fopen("编码完的文件.txt", "w")) == NULL)
           printf("Open file 编码完的文件.txt error!\n");
        char temp;
        while (1)
        {
              fscanf(fp, "%c", &temp);
             printf("%c",temp);
             if(temp=='#')
               break;    //从文件读入下一个字符      
             i=1;
             for (; i <= n; i++)
                 if (HT[i].ch == temp)  //在赫夫曼树中查找字符所在的位置
                  break;   
             for (r = 0; HC[i][r] !='\0'; r++)  //将字符对应的编码存入文件
             {
                 fputc(HC[i][r], fw);
               // putchar(HC[i][r]);
             }          
        }
        printf("\n");
        for(i=1;i<=n;i++)
           printf("%c的编码是: %s\n",HT[i].ch,HC[i]);
          printLine();
         // gotoxy(30,10);
          printf("请点击任意键继续:\n");
        fclose(fw);
        fclose(fp);
        printf("\n已将文件hfmtree.txt成功编码,并已存入编码完的文件.txt中!\n\n");
        getch();
        system("cls"); 
    //    color(5);
        
}
//从文件hfmtree.txt中读入赫夫曼树,返回叶子节点数    赵东炼 
int Read_tree(HuffmanTree &HT)
{
        FILE *fp;
        int i, n;
        HT = (HuffmanTree)malloc(sizeof(HTNode));
        if ((fp = fopen("hfmtree.txt", "r")) == NULL)
           printf("Open file hfmtree.txt error!\n");
        for (i = 1;!feof(fp); i++)
        {
           HT = (HuffmanTree)realloc(HT, (i + 1) * sizeof(HTNode));  //增加空间
           fscanf(fp, "%d %c %d %d %d %d\n",&i,&HT[i].ch,&HT[i].weight,&HT[i].parent,&HT[i].lchild,&HT[i].rchild);
        }
        fclose(fp);
        n = (i + 1) / 2;
        return n;
}
//将文件的代码进行译码,结果存入文件textfile中    罗成 
void Decoding()
{
        FILE *fp, *fw;
        int m, i,ct=0,j=0;
        char text[300],ch,str[300];
        if (n == 0)
           n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数
        if ((fp = fopen("编码完的文件.txt", "r")) == NULL)
             printf("Open file 编码完的文件 error!\n");
        if ((fw = fopen("译码完的文件.txt", "w")) == NULL)
             printf("Open file 译码完的文件.txt error!\n");
        fscanf(fp, "%s", str);
        ch=str[0];
        printf("%s",str);
        printf("\n");
        m = 2 * n - 1;
        while(1)
        {
           if(ch=='0')
             m= HT[m].lchild;
           else
             m=HT[m].rchild;
           if (HT[m].lchild ==0&&HT[m].rchild ==0)//从根结点一直找到叶子
           {
               printf("%c",HT[m].ch);
               text[ct++] = HT[m].ch;
               m = 2 * n - 1;
          }
          j++;
          ch=str[j];
          if(j==strlen(str))
              break;
    }
    if ((HT[m].lchild !=0|| HT[m].rchild != 0) && m != 2 * n - 1)
        printf("编码有误!");
    text[ct]='\0';
    fprintf(fw,"%s",text);
    fclose(fp);
    fclose(fw);
    printf("\n已将编码完的文件成功译码,并且已存入译码完的文件.txt!\n\n");
    getch();
    system("cls");
}
   /*********************对键盘上输入的字符进行解码 ************************/   //     罗成 
void Decode(HuffmanTree &hfmTree,char *ToBeTran, int n)
{
       int i,ct=0;
    char ch;
    printLine(); 
    printf("接下来,根据哈夫曼树进行译码的测试:\n");
    printf("输入需要二进制译文的编码(以#号结束):\n"); 
    scanf("%c", &ch);
    i = 2 * n - 1;//根结点的下标(地址)为2*N-2
    while (ch!='#')//#结束后不再翻译
    {
        if (ch == '0')           //‘0’判断左走
            i = hfmTree[i].lchild;
        else if (ch == '1')      //‘1’判断右走
            i = hfmTree[i].rchild;
        if (hfmTree[i].lchild == 0 || hfmTree[i].rchild == 0)  //从根结点一直找到叶子
        {
            ToBeTran[ct++] = hfmTree[i].ch;             //把i中对应的字符赋值给 
            i = 2 * n - 1;                              //译完一段编码后置为头结点继续翻译
        }
        scanf("%c", &ch);
    }
    if ((hfmTree[i].lchild != 0 || hfmTree[i].rchild != 0) && i != 2 * n- 1)
    printf("编码有误!");
    ToBeTran[ct] = '\0';  
    printf("\n");
    printf("编码译文为:\n");
    printf("%s\n", ToBeTran);
    getch();
    system("cls");     
}
/*************哈夫曼进行编码*******************/    //赵东炼 
void Encode(HuffmanTree &,HuffmanCode HC,int n)
{
        static int flag=0;
        int i, f, c, start,r,j;
        char *cd,str[200];
        {
            HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
            cd = (char *)malloc(n * sizeof(char));
            cd[n - 1] = '\0';
            for (i = 1; i <= n; ++i)
            {
                start = n - 1;
                for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
                if (HT[f].lchild == c)
                   cd[--start] = '0';
                else 
                   cd[--start] = '1';
                HC[i] = (char *)malloc((n - start) * sizeof(char));
                strcpy(HC[i], &cd[start]);
            }
            free(cd);
        }
        printf("\n");
    if(flag==0)
    color(15);
        for(i=1;i<=n;i++)
          printf("%c的编码是: %s\n",HT[i].ch,HC[i]);
          getch();
          system("cls");
          color(9);
          printf("接下来根据哈夫曼树进行编码测试:\n");
          gotoxy(30,10);
          printf("请点击任意键继续。。。\n"); 
          getch(); 
          system("cls"); 
        flag++;
        printf("请输入需要编码的字符串:\n");
        scanf("%s",str);
        printf("该字符串编码为:\n");
        for (i = 0;i<strlen(str); i++)
        {
           for(j=1;j<=n;j++)
             if(str[i]==HT[j].ch)
             {
                flag=j;
                break;
             }      
            printf("%s",HC[flag]);    
        }
        printf("\n");
}

//   打印哈夫曼树         
void Print_tree()
{
   n = Read_tree(HT);
   printfht(2*n-1,n);
}
void printfht(int root,int height)
{
    int m,i;
    n = Read_tree(HT);
    if(root)
    {
        printfht(HT[root].rchild,height+1);
        for(i=0;i<height;i++)
           printf("\t");
        printf("%d",HT[root].weight);
        if(HT[root].lchild==0&&HT[root].rchild==0)
           printf("\\\\%c",HT[root].ch);
        else
           printf("<");     
        printf("\n");
        printfht(HT[root].lchild,height+1);      
    }    
//    getch();
//    system("cls");
}


 

  • 15
    点赞
  • 197
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值