zoukankan      html  css  js  c++  java
  • 怎么实现huffman(哈夫曼编码)以及解码

     一、编码

    【题目描述】

    给定一篇用于通信的英文电文,统计该电文中每个字符出现的频率,按频率左小右大的方法为这些字符建立哈夫曼(Huffamn)树,并编出每个字符的哈夫曼树码,输出该电文的哈夫曼码译文。

    【输入】

    输入文件huffman.in是一篇用于通信的英文电文。

    【输出】

    输出文件huffman.out输出该电文的哈夫曼码译文。

    【输入输出样例1】

    huffman.in                             

    huffman.out

    aaccdddbacbcddddddd

    011011000011101001100010001111111

    【数据限制】

    2<=英文电文字符数<=10000000

    统计以上abcd出现的个数。

    a:3   b:2    c:4    d:10

    构造出哈夫曼树

    a:011         b:010     c  :00          d:1

    下面主要通过两个结构体数组来实现:

    struct node1
    { int w, lch, rch, parent;
    }ht[2*N0-1+1];

    数组下标 1 2 3 4 5 6 7
    父节点的数组下标parent 0 0 0 0      
    左孩子节点的数组下标lch 0 0 0 0      
    右孩子节点的数组下标rch 0 0 0 0      
    权值w 3 2 4 10      

    -》

    数组下标 1 2 3 4 5 6 7
    父节点的数组下标parent 5 5 0 0 0    
    左孩子节点的数组下标lch 0 0 0 0 2    
    右孩子节点的数组下标rch 0 0 0 0 1    
    权值w 3 2 4 10 5    

    -》.。。。。。。。。

    数组下标 1 2 3 4 5 6 7
    父节点的数组下标parent 5 5 6 7 6 7 0
    左孩子节点的数组下标lch 0 0 0 0 2 5 6
    右孩子节点的数组下标rch 0 0 0 0 1 3 4
    权值w 3 2 4 10 5 9 19

    struct node2
    { char ch;//对应的字符abcd
     int start;//编码的起始位置 注意这个编码是倒着的 所以这里用start
     int code[N0];//这个是编码数组
    }hc[N0+1];

    大概图如下面

    美工不好啊 大概将就看了啊

    下面给出大家想要的程序部分

    //#include "stdio.h"
    //#include   "string.h " 
    #include <iostream>
    #include <string>
    const int N0=10;
    const int N=100;
    const int INF=1000000;
    struct node1 
    { int w, lch, rch, parent;
    }ht[2*N0-1+1];
    struct node2
    { char ch;
     int start;
     int code[N0];
    }hc[N0+1];
    int n,root;//n为叶子的个数
    void readData()
    { char ch;
    int num[256]={ 0 };
     n=0;
     freopen( "huffman.in", "r", stdin);//读文本文件
     while( (ch=getchar()) != EOF )
      num[ch]++;
     for( int i=0; i<=255; i++ )
     { if( num[i] )
      { n++;
       ht[n].w=num[i];
       hc[n].ch=i;
      }
     }
    }
    void select1( int t, int *s1, int *s2)//用两个数来记录没有在树上的最小的两个值,从而进一步生成树。
    { int w1,w2;
     w1=w2=INF;
     for( int i=1; i<=t; i++ )
      if( ht[i].parent==0 )
       if( ht[i].w<w1 )
       { w2=w1;
        *s2=*s1;
        w1=ht[i].w;
        *s1=i;
       }
       else if( ht[i].w<w2 )
       { w2=ht[i].w;
        *s2=i;
       }
    }
    
    
    void createHufTreeHuCode()
    { int i, s1, s2;
     int child, parent;
     root=2*n-1;
     for( i=n+1; i<=root; i++)
     { select1(i-1, &s1, &s2 );
      ht[i].w=ht[s1].w+ht[s2].w;
      ht[i].lch=s1;
      ht[i].rch=s2;
      ht[s1].parent=ht[s2].parent=i;
     }
     for(  i=1; i<=n; i++)
     { child=i;
      while( child != root )
      { parent=ht[child].parent;
       if( ht[parent].lch==child )
        hc[i].code[hc[i].start++]=0;
       else 
        hc[i].code[hc[i].start++]=1;
       child=parent;
      }
     }
    
    }
    void txt2code()
    {
     int i,j,m;
     char ch1[N+1]={0};
     freopen( "huffman.in", "r", stdin);
     for (int k=1;k<N+1;k++)
     {
      scanf("%c",&ch1[k]);
     }
     for( j=1,i=1; i<=N; i++)
     { if (ch1[i]==0)
      {
       break;
      }
      while (ch1[i]!=hc[j].ch)
      {
       if (hc[j].ch==0)
       {continue;
       }
       j++;
      }
      for( m=hc[j].start-1; m>=0; m--)
       printf("%d", hc[j].code[m]);
      j=1;
     }
    }
    
    
    int main()
    { 
     readData();
     createHufTreeHuCode();
     freopen("huffman.out", "w", stdout);
     txt2code();
     return 0;
    }
    
    

    二、译码

    【题目描述】

    给定2个输入文件,第1个输入文件是用于通信的英文电文,统计该电文中每个字符出现的频率,按频率左小右大的方法为这些字符建立哈夫曼(Huffamn)树,并编出每个字符的哈夫曼树码;第2个输入文件是已经按第1个输入文件的英文电文编好的哈夫曼码,输出该哈夫曼码的对应的英文电文。

    【输入】

    第1个输入文件为huffman.in是用于通信的英文电文, 第2个输入文件codeToTxt.in是已经按第1个输入文件编好的哈夫曼码。

    【输出】

    输出文件codeToTxt.out输出codeToTxt.in文件内容的英文电文。

    【输入输出样例1】

    huffman.in                            

    codeToTxt.in

    codeToTxt.out

    aaccdddbacbcddddddd

    011111011000011101001100010001111

    adddaccdddbacbcdddd

    【数据限制】

    2<=英文电文字符数<=10000000


     

    #include <iostream>
    #include <string>
    const int N0=10;
    const int N=100;
    const int INF=1000000;
    struct node1 
    { int w, lch, rch, parent;
    }ht[2*N0-1+1];
    struct node2
    { char ch;
     int start;
     int code[N0];
    }hc[N0+1];
    int n,root,num[256];
    void readData()
    { char ch;
    
     n=0;
     freopen( "huffman.in", "r", stdin);
     while( (ch=getchar()) != EOF )
      num[ch]++;//同时得到了两个东西,一个是字符,一个是个数
     for( int i=0; i<=255; i++ )
     { if( num[i] )
      { n++;
       ht[n].w=num[i];//个数
       hc[n].ch=i;//字符
      }
     }
    }
    void select1( int t, int *s1, int *s2)
    { int w1,w2;
     w1=w2=INF;
     for( int i=1; i<=t; i++ )
      if( ht[i].parent==0 )
       if( ht[i].w<w1 )
       { w2=w1;
        *s2=*s1;
        w1=ht[i].w;
        *s1=i;
       }
       else if( ht[i].w<w2 )
       { w2=ht[i].w;
        *s2=i;
       }
    }
    void createHufTreeHuCode()
    { int i, s1, s2;
     int child, parent;
     root=2*n-1;
     for( i=n+1; i<=root; i++)
     { select1( i-1, &s1, &s2 );
      ht[i].w=ht[s1].w+ht[s2].w;
      ht[i].lch=s1;
      ht[i].rch=s2;
      ht[s1].parent=ht[s2].parent=i;
     }
     for(  i=1; i<=n; i++)
     { child=i;
      while( child != root )
      { parent=ht[child].parent;
       if( ht[parent].lch==child )
        hc[i].code[hc[i].start++]=0;
       else 
        hc[i].code[hc[i].start++]=1;
       child=parent;
      }
     }
    
    }
    
    
    void code2txt()
    { char ch=0;
    int i=root;
     freopen( "codeToTxt.in", "r", stdin);
     freopen("codeToTxt.out", "w", stdout);
     while( (ch=getchar()) != EOF )
     {
     
       if(ht[i].lch&&ht[i].rch)
       {if(ch=='0')
        i=ht[i].lch;
       else
        i=ht[i].rch;
       }
       if(ht[i].lch==0&&ht[i].rch==0)
       { printf("%c",hc[i].ch);
        i=root;
       }
        
     }
    }
    
    
    int main()
    { readData();
     createHufTreeHuCode();
     code2txt();
     return 0;
    }
    
    


     

  • 相关阅读:
    Python爬虫利器一之Requests库的用法
    python——时间与时间戳之间的转换
    pyDes库 实现python的des加密
    python 统计发送请求到接收response的时间
    Jenkins进阶系列之——02email-ext邮件通知模板
    Jenkins进阶系列之——01使用email-ext替换Jenkins的默认邮件通知
    Jenkins+Ant+Jmeter搭建持续集成的接口测试平台
    Java连接MySQL数据库——含步骤和代码
    CentOS 7.1 中文正式版下载
    Python数据结构之实现队列
  • 原文地址:https://www.cnblogs.com/lzhp/p/2680792.html
Copyright © 2011-2022 走看看