• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
๑¹¹
博客园    首页    新随笔    联系   管理    订阅  订阅

哈夫曼树编码译码

一、问题描述

    1、问题描述
    利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼码的编/译码系统。
    2、任务要求
    A、初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。

    B、编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。

    C、译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。

    3、测试数据
    A、用下表给出的字符集和频度的实际统计数据建立哈夫曼树。

    B、并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。

二、大致思路

    1、构建哈夫曼树
    有n个字母待建树,申请p[2n-1]个结构体数组空间,将各个字母及其权值存入结构体数组,将数组按照权值进行排序,每次选取最小的两个构建哈夫曼树,每次从上次选择的下一个开始选择,即第一次p[0],p[1]则第二次p[2],p[3],以此类推,每次生成的从p[n+1]开始存入,直至数组就剩下一个元素,即为根节点。
    2、编码
    带权字母即叶子结点,从1步骤的结构体数组那里入手,需要判断一下是否为叶子结点)开始向上回溯即寻找父节点,若为父节点左子树编码为“0”字符,反之为“1”字符,建个数组从最后一位往前存入直至父节点为空即根节点,直至结构体数组最后一个元素。然后将存储的字母的编码和待编码的字符串进行比对,将字符串译码为01结构,编码完成。
    3、译码
    将01结构的编码从根节点开始译码,0往左子树遍历1往右子树,直至叶节点,译码出一个字母,然后再从根节点开始,循环操作直至所有都译码完成。

三、代码实现及结果

    1、具体编译码结果可以查看生成的编码文件以及译码文件。
    2、实现(仅供参考)
    点击查看代码
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    typedef struct node
    {
        char ch[2];
        int weight;
        char ldata,rdata;
        node *lchild,*rchild,*parent;
    }*huffman;
    typedef struct encoding
    {
        char ch[2];
        char *data;
    }*encode1;
    void paixu(huffman *p,int m)
    {
        huffman temp;
        for(int i=0;i<m-1;i++)
        {
            for(int j=i+1;j<m;j++)
            {
                if(p[i]->weight>p[j]->weight)
                {
                    temp=p[i];
                    p[i]=p[j];
                    p[j]=temp;
                }
            }
        }
    }
    huffman* Read(int n)                                                  //读取英文字母
    {
        huffman *huff;
        FILE *fp;
        huff=new huffman[2*n-1];
        for(int i=0;i<2*n-1;i++)
        {
            huff[i]=new node;
            huff[i]->lchild=huff[i]->rchild=NULL;
        }
        if((fp=fopen("hfmTree.txt","w"))==NULL)
        {cout<<"文件打开失败!";exit(0);}
        cout<<"please input the letter:"<<endl;
        for(int i=0;i<n;i++)
        {
            huff[i]->ch[0]=cin.get();
            if(huff[i]->ch[0]=='\n')
            huff[i]->ch[0]=cin.get();
            cin>>huff[i]->weight;
            cin.get();
            huff[i]->ch[1]='\0';
            fprintf(fp,"%s%d ",huff[i]->ch,huff[i]->weight);
        }
        cout<<"hfmTree.txt文件写入完成!"<<endl;
        fclose(fp);
        return huff;
    }
    node* Crhuffman(huffman* p,int n,int *n1)                             //创建哈夫曼树
    {
        int m=n;
        for(int i=0;i<2*n-1;i+=2)
        {
            if((m-1)!=i)
            {
                paixu(p,m);
                p[m]->weight=p[i]->weight+p[i+1]->weight;
                p[m]->lchild=p[i];
                p[m]->rchild=p[i+1];
                p[i]->parent=p[m];
                p[i+1]->parent=p[m];
                m+=1;
            }
            else
            {p[m-1]->parent=NULL;break;}
        }
        *n1=m;
        return p[m-1];
    }
    int Code(huffman *p,int n,int t,char *c,int c1,char *c2)                     //哈弗曼编码
    {
        huffman q;
        FILE *fp;
        q=new node;
        int k=0,k1=t-1,kk=0;
        encode1 *encode;
        encode=new encode1[t];
        for(int i=0;i<t;i++)
        {
            encode[i]=new encoding;
            encode[i]->data=new char[t];
        }
        for(int i=0;i<t;i++)
        {
            for(int j=0;j<t;j++)
            {
                encode[i]->data[j]='a';
            }
        }
        for(int i=0;i<n;i++)
        {
            if(p[i]->lchild==NULL&&p[i]->rchild==NULL)
            {
                q=p[i];
                encode[k]->ch[0]=p[i]->ch[0];
                while(q->parent!=NULL)
                {
                    if(q->parent->lchild==q)
                    encode[k]->data[k1]='0';
                    else
                    encode[k]->data[k1]='1';
                    q=q->parent;
                    k1=k1-1;
                }
                k+=1;
                k1=t-1;
            }
        }
        if((fp=fopen("CodeFile.txt","w"))==NULL)
        {cout<<"文件打开失败!"<<endl;exit(0);}
        for(int i=0;i<t;i++)
        {
            encode[i]->ch[1]='\0';
            fprintf(fp,"%s:",encode[i]->ch);
            for(int j=0;j<t;j++)
            {
                if(encode[i]->data[j]!='a')
                {
                   fprintf(fp,"%c",encode[i]->data[j]);
                   if(j==t-1)
                   fprintf(fp,"\n");
                }
            }
        }
        for(int i=0;i<c1;i++)//编码
        {
            for(int j=0;j<t;j++)
            {
                if(c[i]==encode[j]->ch[0])
                for(int k2=0;k2<t;k2++)
                {
                    if(encode[j]->data[k2]!='a')
                    {
                      c2[kk]=encode[j]->data[k2];
                      kk+=1;
                    }
                }
            }
        }
        c2[kk]='\0';
        fprintf(fp,"#题目所给英文编码: %s",c2);
        cout<<"CodeFile文件写入完成!"<<endl;
        fclose(fp);
        return kk;
    }
    int Readtxt(char *c)                                            //读取英文字符串
    {
        int m=0;
        FILE *fp;
        cout<<"请输入需要编码的大写英文:"<<endl;
        if((fp=fopen("ToBeTran.txt","w"))==NULL)
        {cout<<"文件打开失败!";exit(0);}
        for(int i=0;;i++)
        {
                c[i]=cin.get();
                if(c[i]=='\n')
                {c[i]='\0';break;}
                m+=1;
        }
        fprintf(fp,"%s",c);
        fclose(fp);
        cout<<"ToBeTran.txt文件写入完成!"<<endl;
        return m;
    }
    void Initialization(huffman **p,node **p1,int &n,int &n1)             //初始化
    {
        cout<<"请输入待插入英文字母个数:"<<endl;
        cin>>n;
        *p=Read(n);
        *p1=Crhuffman(*p,n,&n1);
    }
    void Encoding(int &c1,char **c,char **c2,int n,int n1,huffman *p)    //编码
    {
        c1=Readtxt(*c);
        Code(p,n1,n,*c,c1,*c2);
    }
    void Decoding(node *p1,char *c)                                      //译码
    {
        int k=0,i=0;
        FILE *fp;
        node *p=p1;
        if((fp=fopen("TextFile.txt","w"))==NULL)
        {cout<<"文件打开失败!";exit(0);}
        while(c[i]!='\0')
        {
            while(c[i]!='\0')
            {
                if(c[i]=='0')
                {
                    p=p->lchild;
                    if(p->lchild==NULL&&p->rchild==NULL)
                    {i++;break;}
                }
                else
                {
                    p=p->rchild;
                    if(p->lchild==NULL&&p->rchild==NULL)
                    {i++;break;}
                }
                i++;
            }
            fprintf(fp,"%s",p->ch);p=p1;
        }
        fclose(fp);cout<<"TextFile.txt文件写入完成!"<<endl;
    }
    void Print()                                                //打印
    {
        FILE *fp,*fp1;
        char ch[1000];
        if((fp=fopen("CodeFile.txt","r"))==NULL)
        {cout<<"文件打开失败!"<<endl;exit(0);}
        if((fp1=fopen("CodePrint.txt","w"))==NULL)
        {cout<<"文件打开失败!"<<endl;exit(0);}
        while(!feof(fp))
        {
            fscanf(fp,"%s",ch);
            if(ch[0]=='#')
            {
                cout<<ch<<endl;
                fscanf(fp,"%s",ch);
                fprintf(fp1,"%s",ch);
            }
            cout<<ch<<endl;
        }
        fclose(fp);
        fclose(fp1);
    }
    void Tree_printing(node *p1)
    {
        FILE *fp;
        if((fp=fopen("TreePrint.txt","a"))==NULL)
        {cout<<"文件打开失败!"<<endl;exit(0);}
        if(p1)
        {
            if(p1->ch[0]==NULL)
            {
                cout<<"空"<<p1->weight<<"    ";
                fprintf(fp,"空%d\n",p1->weight);
            }
    
            else
            {
                cout<<p1->ch[0]<<p1->weight<<"     ";
                fprintf(fp,"%c%d\n",p1->ch[0],p1->weight);
            }
    
            Tree_printing(p1->lchild);
            Tree_printing(p1->rchild);
        }
    }
    void homepage()
    {
        cout<<"****************************************************************************"<<endl;
        cout<<"               1.Initialization()&&Encoding()    //初始化并编码             "<<endl;
        cout<<"               2.Decoding()                      //译码                     "<<endl;
        cout<<"               3.Print()                         //打印代码文件             "<<endl;
        cout<<"               4.Tree_printing()                 //打印哈夫曼树             "<<endl;
        cout<<"               5.Confirm exit                    //确认退出                 "<<endl;
        cout<<"****************************************************************************"<<endl;
        cout<<"请选择需要的操作:"<<endl;
    }
    void display()
    {
        int N;huffman *p,i=0;
        node *p1;
        encode1 *q;
        char *c,*c2;
        c=new char[100];
        c2=new char[1000];
        int n,n1,c1,n2;
        homepage();
        cin>>N;
        while(1)
        {
             // system("cls");
              if(N==1)
              {
                  Initialization(&p,&p1,n,n1);
                  Encoding(c1,&c,&c2,n,n1,p);
                  i+=1;
              }
              else if(N==2)
              {
                  if(i==0)
                  {cout<<"操作不合法,请重新输入!"<<endl;}
                  else
                  {Decoding(p1,c2);i+=1;}
              }
              else if(N==3)
              {
                  if(i==0)
                  {cout<<"操作不合法,请重新输入!"<<endl;}
                  else
                  {cout<<" ";Print();i+=1;}
              }
              else if(N==4)
              {
                if(i==0)
                {cout<<"操作不合法,请重新输入!"<<endl;}
                else
                {Tree_printing(p1);i+=1;cout<<endl;}
              }
              else if(N==5)
              exit(0);
              else
              printf("输入不合法,请重新输入!\n");
              homepage();
              cin>>N;
        }
    }
    int main()
    {
        display();
    }
    
    3、运行示例

四、小结

    1、可以以%s形式整体写入,注意字符数组末尾要加 `\0` 转为字符串。
    2、结构体数组每个元素都是结构体,指向结构体的二级指针即二级指针存放的是一级指针地址,一级指针存放的是结构体类型数据的地址。
作者:知微smile
出处:https://www.cnblogs.com/zwsmile/p/14150552.html
声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。
posted @ 2019-09-19 22:01  ๑¹¹  阅读(3688)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3