记信息论与编码之课设-哈夫曼编码

来源:互联网 发布:金融互助系统源码 编辑:程序博客网 时间:2024/05/20 16:34

 哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式, 

夫曼编码是可变字长编码(VLC)的一种。Huffman1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)

   首先,将符号按照概率由大到小排队编码时,从最小概率的两个符号开始,可选其中一个支路为0,另一支路为1。这里,我们选上支路为0,下支路为1。再将已编码的两支路的概率合并,并重新排队。多次重复使用上述方法直至合并概率归一时为止   

 从文件中或者输入 读入一个字符串,统计字符串中的字符种类(不包括大小写),以及每个字符出现的概率,并按照霍夫曼编程思想,构造哈夫曼树结构,将其转化成01”的二进制字符串,并且可以读入一串01字符串,将其译为对应的哈夫曼字符。并计算其编码效率。

基本算法:

①  输入字符串 (不包含大小写),回车结束

     ②  根据循环遍历统计字符串中每个不同字符的概率以及总个数

     ③  根据哈夫曼编码构造哈夫曼树

         先将数组排序,采用优先队列求出最小的两个概率,求和得到父节点 ,加入哈夫曼树数组中,依次循环直到只剩下一个概率且为1的根节点

      ④  编码,从每个叶子节点向根遍历,如果是左子树编码就为0,右子树为1.直到所有的叶子节点都编码完毕。

      ⑤   根据公式求编码效率n == H(s)/l

     ⑥  译码 ,根据输入的字符串,从根节点开始想下边遍历,如果是1就向右子树,0就是左子树,直到找到一个叶子节点就退出。继续从根节点开始。

代码如下:

#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<queue>#include<stack>#include<cmath>#include<algorithm>#include<functional>#define max 200using namespace std;struct jcode//求得概率之后的结构体{    char c;    int x;//概率    int b;//下标    friend bool operator<(jcode a, jcode b ){//优先队列排序        return b.x<a.x;    }};typedef jcode jjnum[max];typedef struct bnode{//存储哈夫曼树的结构体数组    char data;    int  x;    int  lchild,rchild,parent;    char code[max];//每个字符编码    int len;//编码长度}bnode;typedef bnode huffman[max];//统计输入的字符及各自概率int  getnum(string ss,jjnum str){    int i,j;    int temp[max];    for(i = 0;i< max;i++)    {        temp[i]=0;    }    for(i = 0;i<ss.length();i++)//求概率         temp[ss[i]-'!']++;    j=0;    for(i = 0;i<max;i++)//存到结构体1    {        if(temp[i]!=0)        {            str[j].x= temp[i];            str[j].c = i+'!';            str[j].b = j;            j++;        }    }    return j;}void create(priority_queue<jcode>q,huffman &t,int cnum,jjnum str)//构造哈夫曼树{    int i,a1,a2;    for(i=0;i<2*cnum-1;i++)//初始化结点    {       t[i].lchild = t[i].parent = t[i].rchild = t[i].x  = 0;       t[i].data= '1';    }    for(i=0;i<cnum;i++)//叶子节点    {        t[i].x = str[i].x;        t[i].data = str[i].c;    }    for(i=cnum;i<2*cnum-1;i++)//根据哈夫曼编码构造哈夫曼树    {        a1 = q.top().b;        t[a1].parent = i;q.pop();        a2 = q.top().b;        t[a2].parent = i;q.pop();        t[i].lchild = a1;//指向孩子        t[i].rchild = a2;        t[i].x = t[a1].x+t[a2].x;//概率小的两个相加        jcode e;        e.c = '1';e.x = t[i].x;e.b = i;        q.push(e);//和存到队列中    }    for(i=0;i<cnum;i++)//由0.1进行二元编码,1右0左    {        int x;        x=i;        t[i].len = 0;        while(t[x].parent!=0)//从叶子节点向根        {            if(t[t[x].parent].lchild == x)            {                t[i].code[t[i].len]='0';//存下来编码                t[i].len++;            }            else            {                t[i].code[t[i].len]='1';                t[i].len++;            }            x = t[x].parent;        }    }    for(i=0;i<cnum;i++)//输出每个字符编码    {        if(t[i].data!='1')        {          cout<<t[i].data<<"  ===  ";          for(int j=t[i].len-1;j>=0;j--)            cout<<t[i].code[j];          cout<<endl;        }    }}//编码fvoid strhttree(jjnum str,int num,huffman &t){    int i;    priority_queue<jcode>q2;    for(i = 0; i < num; i++)//加入优先队列        q2.push(str[i]);    create(q2,t,num,str);}void yima(string ss,int i,huffman &t,int num,int cnum)//译码{    while(num>=cnum)//从根节点开始    {      if(ss[i]=='1')      {          num = t[num].rchild;          i++;      }      else     {          num = t[num].lchild;          i++;      }    }    if(i<=ss.length())//得到一个叶子节点,即译出一个字符    {      cout<<t[num].data;      yima(ss,i,t,2*cnum-2,cnum);//继续译码    }}int main(){    string s;//输入字符串    huffman t;//哈夫曼树    getline(cin,s);    jcode str[max];    int cnum = getnum(s,str);//字符的种类个数    strhttree(str,cnum,t);//构造哈夫曼树    for(int k = 0;k<s.length();k++)//输出编码        for(int i=0;i<cnum;i++)       {           if(s[k]==t[i].data){             for(int j=t[i].len-1;j>=0;j--)               cout<<t[i].code[j];           }       }    cout<<endl;    double sum1 =0.0,sum2 = 0.0;    for(int i = 0;i<cnum;i++)//求编码效率    {       sum1+=((t[i].x*1.0/s.size())*(-log2(t[i].x*1.0/s.size())));        sum2+=(t[i].x*1.0/s.size())*t[i].len;    }    cout<<"n=="<<(sum1/sum2)<<endl;    string l;    getline(cin,l);//输入码    int x= 2*cnum -2;//根节点、    yima(l,0,t,x,cnum);//译码    return 0;}


1 0
原创粉丝点击