霍夫曼编码与解码

来源:互联网 发布:域名未授权 编辑:程序博客网 时间:2024/06/08 11:14


  压缩软件:

  给定一篇文章,只含有英文大小写字母和空格,统计该文件中各种字符的频率,对各字符进行Huffman编码,将该文件翻译成Huffman编码文件,再将Huffman编  码文件翻译成源文件。

运行结果如下

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef struct{    int value;    int p,l,r;}HTNode,*HuffTree;struct fact                   //因为不是每一篇文章中所有字符都会出现{                            //所以结构体数组存储数组下标真正对应的字符ch以及权值weight    char ch;    int weight;};typedef char * * HuffCode;   //  字符指针数组用于存储各个字符对应的编码typedef char * CHAR;void select(HuffTree &HT,int n,int &s1,int &s2);                         //查找HT中未被使用的权值最小的连个点的下标void HUFFTREE(HuffTree &HT,fact *ww,int n,HuffCode &HC);                //建树函数,附带完成每一个字符对应的编码void BecomeCode(HuffCode &HC,int n,CHAR &Code,char *Text,int *match);  //由已知的各个字符的编码完成全文的编码void Code_ToBe_Artical(CHAR &Code,HuffTree &HT,fact *Fact,int n);     //由全文的编码,用已经建立的哈弗曼树完成解码int main(){    HuffTree HT=NULL;    HuffCode  HC;    printf("请输入需要编码的文章\n");    char Text[20000];    CHAR Code = NULL;               //指针用于存储文章最终的编码    gets(Text);    int len=strlen(Text);    int codeweight[54],match[54];    memset(codeweight,0,sizeof(codeweight));    for(int i=0;i<len;i++)          // 统计频率  空格下标为0 ,(A~Z)下标分别为(1~26) (a~z)下标分别为(27~52)    {       if(Text[i]==' ')           codeweight[0]++;        else if(isupper(Text[i]))            codeweight[Text[i]-'A'+1]++;        else            codeweight[Text[i]-'a'+27]++;    }    int n=0;    fact Fact[54];                  // 由于不是每一个字符都出现在文章中,将codeweight数组录入Fact结构体数组中    for(int i=0;i<=52;i++)    {        if(codeweight[i]!=0)        {            if(i==0)            Fact[n].ch=' ';            else if(i<=26)            Fact[n].ch=i+'A'-1;            else            Fact[n].ch=i+'a'-27;            match[i]=n;            Fact[n++].weight=codeweight[i];        }    }    HUFFTREE(HT,Fact,n,HC);                //建树函数,附带完成每一个字符对应的编码    BecomeCode(HC,n,Code,Text,match);     //由已知的各个字符的编码完成全文的编码    Code_ToBe_Artical(Code,HT,Fact,n);   //由全文的编码,用已经建立的哈弗曼树完成解码    return 0;}void select(HuffTree &HT,int n,int &s1,int &s2){    s1=s2=0;    HT[0].value=0x7fffffff;    for(int i=1;i<=n;i++)    {        if(HT[i].p!=0)            continue;        if(HT[i].value<HT[s1].value)        {            s2=s1;            s1=i;        }        else if(HT[i].value<HT[s2].value)            s2=i;    }}void HUFFTREE(HuffTree &HT,fact *ww,int n,HuffCode &HC){    int m=n*2-1;    HT = (HuffTree)malloc((m+1)*sizeof(HTNode));  //分配m+1个内存,是因为要存储m个数据,但是要从HT数组下标1开始    int i,j,f;    fact *w=ww;    HuffTree p;    for(p =HT,p++,i=1;i<=n;i++,p++,w++)          //对HT (1~n)赋值语句    {        (*p).value=(*w).weight,(*p).p=0,(*p).l=0,(*p).r=0;    }    for(;i<=m;i++,p++)                          //对HT (n+1~m)赋值语句    {        (*p).value=0,(*p).p=0,(*p).l=0,(*p).r=0;    }    int s1,s2;    for(i=n+1;i<=m;i++)    {        select(HT,i-1,s1,s2);        HT[s1].p=i,HT[s2].p=i;        HT[i].l=s1,HT[i].r=s2;        HT[i].value=HT[s1].value+HT[s2].value;    }   HC = (HuffCode)malloc((n+1)*sizeof(char *));    // 为字符指针数组分配内存   char *temp=(char *)malloc(n*sizeof(char));   temp[n-1]='\0';   for(i=1;i<=n;i++)   {       int start=n-2;       for(j=i,f=HT[i].p;f!=0;j=f,f=HT[f].p)       {           if(HT[f].l==j)            temp[start--]='0';           else            temp[start--]='1';       }       HC[i]=(char *)malloc((n-start)*sizeof(char));       strcpy(HC[i],&temp[++start]);   }   delete temp;   printf("\n各个字符对应的编码\n");   for(i=1;i<=n;i++)   {       if(ww[i-1].ch==' ')        printf("空格 --> ");       else        printf("%c --> ",ww[i-1].ch);       puts(HC[i]);   }}void BecomeCode(HuffCode &HC,int n,CHAR &Code,char *Text,int *match){    int len,i;                           //纯粹是用已知的文本Text和HC将文本转化为编码    len=strlen(Text);    Code = (char *)malloc((len*n+1)*sizeof(char));    Code[0]='\0';    for(i=0;i<len;i++)    {        if(Text[i]==' ')            strcat(Code,HC[1]);        else if(Text[i]<='Z'&&Text[i]>='A')            strcat(Code,HC[ match[Text[i]-'A'+1]+1 ]);        else            strcat(Code,HC[ match[Text[i]-'a'+27]+1 ]);    }    printf("\n文章编码为\n");    puts(Code);}void  Code_ToBe_Artical(CHAR &Code,HuffTree &HT,fact *Fact,int n)  //纯粹的使用已经建好的树,由上至下进行查询{    printf("\n将编码解码\n");    for(int i=0;Code[i]!='\0';i++)    {       int m=n*2-1,ok=1;       while(1)       {         if(Code[i]=='0')         {            m=HT[m].l;            if(HT[m].l==0)              {                printf("%c",Fact[m-1].ch);                break;              }         }         else if(Code[i]=='1')         {             m=HT[m].r;             if(HT[m].r==0)                {                    printf("%c",Fact[m-1].ch);                    ok=0;                }         }         if(!ok)            break;         i++;       }    }    printf("\n");    return ;}







0 0
原创粉丝点击