zoukankan      html  css  js  c++  java
  • Huffman压缩和解压

     Huffman压缩和解压

    一、      需求分析

    1.        本演示程序中,模拟的是小写26个英文字母的Huffman压缩,字母小随机函数随机产生,后统计字母个数建立Huffman树,用建立Huffman树将字母转为二进制流,再将二进制流每次分8个转为一个Unsigned Char写入物理内存!

    2.        解压时建立同样的Huffman树或读取已保存的Huffman树,通过将读取的Unsigned Char转为比特流,再由比特流得到原被压缩的字母

    3.        程序执行的命令有:随机文件的产生,文件统计,Huffman树的建立,压缩,解压,程序的运行过程和其它信息的文件存储!

    4.        程序测试:运行程序,产生随机文件input.txt,压缩时得到的比特流bytes.txt,压缩文件compress.txt,解压时到得的比特流uncompress.txt,解压后文件output.txt和程序的运行过程文件Run.txt,其中红色文件为可无文件

    二、      概要设计

    1.        为达到压缩效果,采用Huffman树来进行编码压缩

    2.        Huffman编码后若直接保存比特流至txt将达不到压缩的效果,因此建议将比特流转为Unsigned char 来间接存储以达到明显的压缩效果

    3.        解压时因用到之前的Huffman树,因此在压缩时有必要保存树的状态

    4.        Huffman树在压缩时直接使用对应编码即可,在解压时通过遍历树来得到被编码的字母

    三、      详细设计

    1.        树结构体的定义和全局变量的定义:

    typedef struct HTNode{/*Huffman Tree 的结构定义*/

        unsigned int weight;

        unsigned int parent, lchild, rchild;

    }HTNode,* HuffmanTree;

    typedef char** HuffmanCode;/*指向字符指针的指针的数据的定义*/

    int stat[27];/*存储总数,存储26个字母出现的次数*/

    HuffmanTree HT;

            HuffmanCode HC;

    2.        随机文件的产生函数:

    void CreatFile(){/*自动产生文件*/

        FILE *Fopen,*Fout;

        int i;

        srand( (unsigned)time(NULL));

        Fout=fopen("./Run.txt","w");

        fprintf(Fout,"NO.1: Creating a file by rand()"n");

        Fopen = fopen("./input.txt", "w");

        for(i=0; i<10000; i++){

            char ch=(char)(97+rand()%26);

            fputc(ch, Fopen);

           }

        fclose(Fopen);

        fclose(Fout);

    }

    3.        字母个数的统计:

    void ReadStat(char *Filename){/*每个字符出现的次数统计*/

        int c;

        FILE *Fopen=fopen(Filename, "r");

        while((c=fgetc(Fopen))!=EOF){

            stat[c%96]++;

            stat[0]++;

        }

    }

    4.        选择HT[1i-1]Parent0Weight最小的一个点的函数:

    void Select(HuffmanTree HT, int d, int *s){

        int temp=0,i;

        for(i=1; i<=d; i++){

               if(HT[i].parent!=0)

                      continue;

               if(temp==0)

                      temp=i;

               else if(HT[temp].weight>HT[i].weight)

                      temp=i;

        }

        *s=temp;

    }

    5.        Huffman树的建立函数:

    void HuffmanCoding(int* w, int n){

        int m= 2*n-1;

        int i, s1, s2, start;

        unsigned int c, f;

        char *cd;

        if(n<=1)

               return;

        HT=(HTNode*)malloc((m+1)*sizeof(HTNode));/*0号单元未用*/

        for(i=1; i<=n; i++, w++){

               /***p={*w,0,0,0}; 初始化*/

               HT[i].weight=*w;

               HT[i].parent=0;

               HT[i].lchild=0;

               HT[i].rchild=0;

        }

        for(; i<=m; i++){

               /**p={0,0,0,0};*/

               HT[i].weight=*w;

               HT[i].parent=0;

               HT[i].lchild=0;

               HT[i].rchild=0;

        }

        for(i=n+1; i<=m; i++){

               Select(HT, i-1, &s1);/*选择HT[1i-1]Parent0Weight最小的一个点*/

               HT[s1].parent=i;

               Select(HT, i-1, &s2);

               HT[s2].parent=i;

               HT[i].lchild=s1;/*左右孩子对编码没有影响,也说明的Huffman树的不唯一性*/

               HT[i].rchild=s2;

               HT[i].weight= HT[s1].weight + HT[s2].weight;

        }

        HC = (HuffmanCode) malloc ((n+1) * sizeof(char*));/*分配n个字符编码的头指针向量*/

        cd = (char*) malloc(n*sizeof(char));

        cd[n-1]='"0';

        for(i=1; i<=n; i++){

               start =n-1;

               for(c=i, f=HT[i].parent; f!=0; c=f, f=HT[f].parent)

                      if(HT[f].lchild==c)

                             cd[--start]='0';

                      else

                             cd[--start]='1';

               HC[i]=(char*)malloc((n-start)*sizeof(char));

               strcpy(HC[i], &cd[start]);

        }

        free(cd);

    }

    6.        Huffman树的存储:

    void WriteCode(){

        FILE *Fopen;

        int i;

        Fopen=fopen("./Run.txt","a+");

        fprintf(Fopen,"NO.2: The array of the structure of HuffmanTree:"n");

        for(i=1;i<52;i++)

               fprintf(Fopen,"%-2d: p:%-3d w:%-5d l:%-3d r:%-3d"n",i, HT[i].parent,HT[i].weight,HT[i].lchild,HT[i].rchild);

        fprintf(Fopen,"NO.3: The Huffman codes:"n");

        for(i=1;i<27;i++)

               fprintf(Fopen,"%c: %3d %s"n",'a'+i-1,stat[i],HC[i]);

    }

    7.        输出压缩前应该得到的比特流:

    void OutCompress(){

        FILE *Fin,*Fout;

        int c;

        Fin=fopen("./input.txt","r");

        Fout=fopen("./bytes.txt","w");

        if(Fin==NULL)

               printf("Can't find the file of 'input'!"n");

        while((c=fgetc(Fin))!=EOF){/*output the bit stream*/

               fprintf(Fout,"%s",HC[c-96]);

        }

        fclose(Fin);

        fclose(Fout);

    }

    8.        压缩函数:

    void Compress(){

        FILE *Fin,*Fout;

        unsigned char out=0;

        char c,*buf;

        int i,count=0;

        buf=(char *)malloc(sizeof(char)*20);

        Fin=fopen("./input.txt","r");

        Fout=fopen("./compress.txt","wb");

        if(Fin==NULL)

               printf("Can't find the file of 'input'!"n");

        while((c=fgetc(Fin))!=EOF){/*output the bit stream*/

               buf=HC[c-96];

               for(i=0;buf[i]!='"0';i++){

                      if(count==8){

                    fprintf(Fout,"%c",out);

                             count=0;

                             out=0;

                      }

                      out<<=1;

                      count++;

                      if(buf[i]=='1')

                             out=out|1;

               }

        }

        if(count!=8){

               out<<=(8-count);

               fprintf(Fout,"%c",out);

        }

        fclose(Fin);

        fclose(Fout);

    }

    9.        解压函数:

    void UnCompress(){

        FILE *Fin,*Fout,*Fout1;

        unsigned char c=0,*buf;

        int i,k,t=51;

        buf=(char *)malloc(sizeof(char)*10);

        Fin=fopen("./compress.txt","rb");

        Fout=fopen("./uncompress.txt","wb");

        Fout1=fopen("./output.txt","wb");

        if(Fin==NULL)

               printf("Can't find the file of 'input'!"n");

        while(!feof(Fin)){/*output the bit stream*/

            c=fgetc(Fin);

               for(i=7;i>=0;i--){

                      k=(c>>i)&1;

                      fprintf(Fout,"%d",k);

                      if(k==0)

                    t=HT[t].lchild;

                else

                    t=HT[t].rchild;

                if(HT[t].lchild==0&&HT[t].rchild==0){

                    fprintf(Fout1,"%c",96+t);

                    t=51;

                }

               }

        }

        fclose(Fin);

        fclose(Fout);

    }

    10.    主函数入口

    int main(int arg, char *argv[]){/*存放Huffman编码*/

        CreatFile();

        ReadStat("./input.txt");

        HuffmanCoding(&stat[1], 26);

        WriteCode();

        OutCompress();

        Compress();

        UnCompress();

        system("Echo Pree any key to kill the program");

        system("PAUSE>NUL 2>NUL");

    }

    四、      调试分析

    1.        二进制流与unsigned char之间的转换,采用的是位操作,而不是进制的转换,导致失败

    2.        位操作的使用出错,将c<<1错误理解为对C的左移,导致无法成功压缩,后改为C=<<1即可

    3.        文件的读入方式有二进制读入和文本读入,当压缩文件中写入^Z(文本文件结束标志)后,文本方式读取压缩文件失败,最后使用二进制读取成功

    4.        文件的压缩效率问题上我考虑过用unsigned int来替换unsigned char,但结果是失败的,压缩率反而降低

    5.        由于比特流中二进制数%sizeof(unsigned char)不一定为零,此异常(解压文件结尾处会多出2个字符)处理仍没有得到有效解决

    6.        因为输入文件是随机为生,每个字母出现的频率相近,因此得到的Huffman编码长度也基本相同,在这种情况也就是最差的情况下,最后压缩率达到60%,让人振奋!

    五、      测试结果:

       经多次按要求合法测试,测试程序执行的无误,压缩率也在60%以下,下面是测试结果的一个范例:

           其中输入文件大小为10,000个随机字母,大小为:10,000 字节

           产生的压缩文件大小为:5,939 字节

           解压后文件大小仍为:10,000 字节

           压缩率接近:59.4%

    六、      附录(源程序清单)

     源代码:Huffman.C           产生的文件有:

    input.txt

    被压缩文件

    output.txt

    解压后文件

    compress.txt

    压缩后文件

    bytes.txt

    压缩时的比特流

    uncompress.txt

    解压时得到的比特流

    Run.txt

    程序运行过程记录

    代码如下:(讨厌不看只抄的人)

    Code
  • 相关阅读:
    AcWing 204. 表达整数的奇怪方式 / Strange Way To Express Integers
    Codeforces Edu Round 67 A-C + E
    Codeforces Edu Round 66 A-E
    Codeforces Edu Round 65 A-E
    Codeforces Edu Round 64 A-D
    Codeforces Edu Round 63 A-E
    Codeforces Edu Round 62 A-E
    Codeforces Edu Round 61 A-C + F
    python 线程池和锁
    python 线程
  • 原文地址:https://www.cnblogs.com/yequan/p/1487315.html
Copyright © 2011-2022 走看看