• 哈夫曼编码及其解码


    添加注释版本:

    /*
    cout<<i<<endl<<" 结点 | data | weight | lchild | rchild | parent "<<endl; 
    for(int i=1;i<=m;++i)
    {
        cout<<i<<" | "<<HT[i].data<<" | "<<HT[i].weight<<" | "<<HT[i].lchild<<" | "<<HT[i].rchild<<" | "<<HT[i].parent<<endl;
    }
    */
    #include<iostream>
    #include<stdio.h>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #define MAX 0x3f3f3f3f 
    using namespace std;
    
    typedef struct
    {
        char data;
        int weight;
        int parent;
        int lchild;
        int rchild;
        bool tag;
    }Huffnode,*HuffmanTree;
    typedef struct
    {
        string *code;//存放字符的编码 
        char *data;//存放字符 
        int num;//存放一共有多少字符 
    }HuffmanCode;
    void DisplayHuffmanCode(HuffmanCode &HC,int n)
    {
        for(int i=0;i<n;++i)
        {
            cout<<HC.code[i]<<endl;
        }
    }
    void Select(HuffmanTree &HT,int index, int &s1, int &s2)
    {
        int min1=MAX;
        int min2=MAX;
        for(int i=1;i<=index;++i)
        {
            if(HT[i].parent==0&&HT[i].tag)
            {
                if(HT[i].weight<min1)
                {
                    s1=i;
                    min1=HT[i].weight;
                }
            }
        }
        HT[s1].tag=0;//表明此节点已经被选中过 
        for(int i=1;i<=index;++i)
        {
            if(HT[i].parent==0&&HT[i].tag)
            {
                if(HT[i].weight<min2)
                {
                    s2=i;
                    min2=HT[i].weight;
                }
            }
        }
        HT[s2].tag=0; 
    }
    void CreatHuffmanTree(HuffmanTree &HT,int n)
    {
        /*n:待编码数有多少*/
        if(n<=1)return;
        int m=2*n-1; //计算节点个数
        HT=new Huffnode[m+1];//0号单元未用,HT[m]表示根结点,从1开始存放数据 
        //初始化哈夫曼表
        for(int i=1;i<=m;++i)
        {
            HT[i].lchild=0;
            HT[i].rchild=0;
            HT[i].parent=0;
            HT[i].tag=1;
            HT[i].data='';
        }
        //依次输入待编码的数据的权重 
        cout<<"请依次输入每一个字和它的权重:"<<endl;
        for(int i=1;i<=n;++i)
        {
            scanf("%c",&HT[i].data);
            getchar();
            scanf("%d",&HT[i].weight);
            getchar();
    //        cin>>HT[i].data>>HT[i].weight;
        }
         //构造  Huffman树
        int s1,s2;
        for(int i=n+1;i<=m;++i)      
        {
            Select(HT,i-1,s1,s2);
            //在已经有数据的哈夫曼节点中,选择两个双亲域为0,且权值最小的结点
            //并返回它们在HT中的序号s1和s2
            HT[s1].parent=i;
            HT[s2].parent=i;  
             //表示从F中删除s1,s2
            HT[i].lchild=s1;    
            HT[i].rchild=s2; 
             //s1,s2分别作为i的左右孩子
            HT[i].weight=HT[s1].weight + HT[s2].weight;
             //i 的权值为左右孩子权值之和
        }
        cout<<" 结点 | data | weight | lchild | rchild | parent "<<endl; 
        for(int i=1;i<=m;++i)
        {
            cout<<i<<" | "<<HT[i].data<<" | "<<HT[i].weight<<" | "<<HT[i].lchild<<" | "<<HT[i].rchild<<" | "<<HT[i].parent<<endl;
        }
    }
    //根据创建的哈夫曼树,从叶子到根逆向求每个字符的赫夫曼编码,存储在编码表HC中
    void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n)
    {
        /*n:代表编码个数*/
        HC.code=new string[n+1];                 //分配n个指向字符串的指针
        HC.data=new char[n+1];
        HC.num=n+1;//从1开始存 
         
        for(int i=1; i<=n; ++i)
        {    //逐个字符求赫夫曼编码
            int c=i; //哈夫曼表的下标
            int f=HT[i].parent;
            string cd="";
            while(f!=0)
            {    //从叶子结点开始向上回溯,直到根结点
                 if (HT[f].lchild==c)  
                 {
                     cd+="0";    //结点c是f的左孩子,则生成代码0
                 }
                 else 
                 {
                     cd+="1"; //结点c是f的右孩子,则生成代码1
                 }
                 c=f; //跟新孩子,找上一代
                 f=HT[f].parent;                     //继续向上回溯
            }     
            reverse(cd.begin(),cd.end());
            HC.code[i]=cd;   //将求得的编码从临时空间cd复制到HC的当前行中
    //        cout<<cd<<endl; 
          }
          cout<<"当前的哈夫曼编码表为:"<<endl;
          for(int i=1;i<=n;++i)
          {
              HC.data[i]=HT[i].data;
              cout<<i<<" | "<<HC.data[i]<<" | "<<HC.code[i]<<endl;
              
          }
    } 
    void Encoding(HuffmanCode HC,string str)
    {
        cout<<"编码结果为:"<<endl; 
        for(int i=0;i<str.length();++i)
        {
            for(int j=1;j<=HC.num;++j)
            {
    //            cout<<"
    HC.data[j]==str[i]"<<HC.data[j]<<" "<<str[i]<<endl; 
                if(HC.data[j]==str[i])
                {
                    cout<<HC.code[j];
                    break; 
                }
            }
            
         } 
    }
    void Decoding(HuffmanCode HC,string str)
    {
        cout<<"解码结果为:"<<endl; 
        string temp="";
        int postion=0;
        for(int i=0;i<str.length();)
        {
            for(int j=1;j<=HC.num;++j)
            {
                int k=0;
    //            cout<<"
    当前查找的是:"<<HC.code[j]; 
                for(;k<HC.code[j].length();++k)
                {
    //                cout<<" HC.code[j][k]!=str[i] "<<HC.code[j][k]<<","<<str[i+k]; 
                    if(HC.code[j][k]!=str[i+k])
                    {
                        break;
                    }
                }
    //            cout<<" k="<<k<<endl;
                if(k==HC.code[j].length())
                {
                    i+=HC.code[j].length();
                    cout<<HC.data[j];
                    break;
                }
            }
         } 
    }
    int main()
    {
        HuffmanTree HT;
        HuffmanCode HC;
        //构造赫夫曼树,输出各字符的赫夫曼编码
        cout<<"
    请输入编码的个数:"<<endl;
        int n=0;
        cin>>n; 
        getchar();
        CreatHuffmanTree(HT,n);
        CreatHuffmanCode(HT,HC,n);
        //     编码:输入字符序列,输出对应的赫码序列。
        cout<<"
    请输入要编码的字符:"<<endl;
        string e_str="";
        getline(cin,e_str);
        Encoding(HC,e_str);
    //    cout<<e_str<<endl;
        // 译码:输入赫夫曼码序列,输出原始字符代码。
        cout<<"
    请输入要解码的字符:"<<endl;
        string d_str="";
        getline(cin,d_str);
        Decoding(HC,d_str);
         
    }
    View Code

    未加注释清爽版:

      1 #include<iostream>
      2 #include<stdio.h>
      3 #include<string>
      4 #include<cstring>
      5 #include<algorithm>
      6 #define MAX 0x3f3f3f3f 
      7 using namespace std;
      8 
      9 typedef struct
     10 {
     11     char data;
     12     int weight;
     13     int parent;
     14     int lchild;
     15     int rchild;
     16     bool tag;
     17 }Huffnode,*HuffmanTree;
     18 typedef struct
     19 {
     20     string *code;
     21     char *data;
     22     int num;
     23 }HuffmanCode;
     24 void DisplayHuffmanCode(HuffmanCode &HC,int n)
     25 {
     26     for(int i=0;i<n;++i)
     27     {
     28         cout<<HC.code[i]<<endl;
     29     }
     30 }
     31 void Select(HuffmanTree &HT,int index, int &s1, int &s2)
     32 {
     33     int min1=MAX;
     34     int min2=MAX;
     35     for(int i=1;i<=index;++i)
     36     {
     37         if(HT[i].parent==0&&HT[i].tag)
     38         {
     39             if(HT[i].weight<min1)
     40             {
     41                 s1=i;
     42                 min1=HT[i].weight;
     43             }
     44         }
     45     }
     46     HT[s1].tag=0;
     47     for(int i=1;i<=index;++i)
     48     {
     49         if(HT[i].parent==0&&HT[i].tag)
     50         {
     51             if(HT[i].weight<min2)
     52             {
     53                 s2=i;
     54                 min2=HT[i].weight;
     55             }
     56         }
     57     }
     58     HT[s2].tag=0; 
     59 }
     60 void CreatHuffmanTree(HuffmanTree &HT,int n)
     61 {
     62     if(n<=1)return;
     63     int m=2*n-1;
     64     HT=new Huffnode[m+1];
     65 
     66     for(int i=1;i<=m;++i)
     67     {
     68         HT[i].lchild=0;
     69         HT[i].rchild=0;
     70         HT[i].parent=0;
     71         HT[i].tag=1;
     72         HT[i].data='';
     73     }
     74     cout<<"请依次输入每一个字和它的权重:"<<endl;
     75     for(int i=1;i<=n;++i)
     76     {
     77         scanf("%c",&HT[i].data);
     78         getchar();
     79         scanf("%d",&HT[i].weight);
     80         getchar();
     81     }
     82 
     83     int s1,s2;
     84     for(int i=n+1;i<=m;++i)      
     85     {
     86         Select(HT,i-1,s1,s2);
     87         HT[s1].parent=i;
     88         HT[s2].parent=i;  
     89         HT[i].lchild=s1;    
     90         HT[i].rchild=s2; 
     91         HT[i].weight=HT[s1].weight + HT[s2].weight;
     92     }
     93 }
     94 void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n)
     95 {
     96 
     97     HC.code=new string[n+1];
     98     HC.data=new char[n+1];
     99     HC.num=n+1;
    100      
    101     for(int i=1; i<=n; ++i)
    102     {
    103         int c=i; 
    104         int f=HT[i].parent;
    105         string cd="";
    106         while(f!=0)
    107         {
    108              if (HT[f].lchild==c)  
    109              {
    110                  cd+="0";
    111              }
    112              else 
    113              {
    114                  cd+="1";
    115              }
    116              c=f;
    117              f=HT[f].parent;
    118         }     
    119         reverse(cd.begin(),cd.end());
    120         HC.code[i]=cd;
    121       }
    122       cout<<"当前的哈夫曼编码表为:"<<endl;
    123       for(int i=1;i<=n;++i)
    124       {
    125           HC.data[i]=HT[i].data;
    126           cout<<i<<" | "<<HC.data[i]<<" | "<<HC.code[i]<<endl;
    127           
    128       }
    129 } 
    130 void Encoding(HuffmanCode HC,string str)
    131 {
    132     cout<<"编码结果为:"<<endl; 
    133     for(int i=0;i<str.length();++i)
    134     {
    135         for(int j=1;j<=HC.num;++j)
    136         {
    137             if(HC.data[j]==str[i])
    138             {
    139                 cout<<HC.code[j];
    140                 break; 
    141             }
    142         }
    143         
    144      } 
    145 }
    146 void Decoding(HuffmanCode HC,string str)
    147 {
    148     cout<<"解码结果为:"<<endl; 
    149     string temp="";
    150     int postion=0;
    151     for(int i=0;i<str.length();)
    152     {
    153         for(int j=1;j<=HC.num;++j)
    154         {
    155             int k=0;
    156             for(;k<HC.code[j].length();++k)
    157             {
    158                 if(HC.code[j][k]!=str[i+k])
    159                 {
    160                     break;
    161                 }
    162             }
    163             if(k==HC.code[j].length())
    164             {
    165                 i+=HC.code[j].length();
    166                 cout<<HC.data[j];
    167                 break;
    168             }
    169         }
    170      } 
    171 }
    172 int main()
    173 {
    174     HuffmanTree HT;
    175     HuffmanCode HC;
    176     //构造赫夫曼树,输出各字符的赫夫曼编码
    177     cout<<"
    请输入编码的个数:"<<endl;
    178     int n=0;
    179     cin>>n; 
    180     getchar();
    181     CreatHuffmanTree(HT,n);
    182     CreatHuffmanCode(HT,HC,n);
    183     // 编码:输入字符序列,输出对应的赫码序列。
    184     cout<<"
    请输入要编码的字符:"<<endl;
    185     string e_str="";
    186     getline(cin,e_str);
    187     Encoding(HC,e_str);
    188     // 译码:输入赫夫曼码序列,输出原始字符代码。
    189     cout<<"
    请输入要解码的字符:"<<endl;
    190     string d_str="";
    191     getline(cin,d_str);
    192     Decoding(HC,d_str);
    193      
    194 }

    测试样例:

    输入:

    27

    输入:

     
    186
    a
    64
    b
    13
    c
    22
    d
    32
    e
    103
    f
    21
    g
    15
    h
    47
    i
    57
    j
    1
    k
    5
    l
    32
    m
    20
    n
    56
    o
    63
    P
    15
    q
    1
    r
    48
    s
    51
    t
    80
    u
    23
    v
    8
    w
    18
    x
    1
    y
    16
    z
    1
    View Code

    输入:

    you are bad gay but laolao is not

    输入:

    1000111001000011111010001001011110000010101011011110000110101000111111000000000111011111011110101001101111010100111101110011111011010011101

    输出:

  • 相关阅读:
    bootstap 折叠
    AtCoder AGC019E Shuffle and Swap (DP、FFT、多项式求逆、多项式快速幂)
    Codeforces Gym 101630J Journey from Petersburg to Moscow (最短路)
    BZOJ 4042 Luogu P4757 [CERC2014]Parades (树形DP、状压DP)
    BZOJ 2734 [HNOI2012]集合选数 (状压DP、时间复杂度分析)
    BZOJ 2759 一个动态树好题 (LCT)
    Codeforces 1205C Palindromic Paths (交互题、DP)
    getopt实现传参自动识别
    powershell笔记
    bat语法需要注意的地方
  • 原文地址:https://www.cnblogs.com/chrysanthemum/p/11830506.html
Copyright © 2020-2023  润新知