利用哈夫曼编码实现压缩和解压缩

合集下载

哈夫曼编解码压缩解压文件—C++实现

哈夫曼编解码压缩解压文件—C++实现

哈夫曼编解码压缩解压⽂件—C++实现前⾔哈夫曼编码是⼀种贪⼼算法和⼆叉树结合的字符编码⽅式,具有⼴泛的应⽤背景,最直观的是⽂件压缩。

本⽂主要讲述如何⽤哈夫曼编解码实现⽂件的压缩和解压,并给出代码实现。

哈夫曼编码的概念哈夫曼树⼜称作最优树,是⼀种带权路径长度最短的树,⽽通过哈夫曼树构造出的编码⽅式称作哈夫曼编码。

也就是说哈夫曼编码是⼀个通过哈夫曼树进⾏的⼀种编码,⼀般情况下,以字符 “0” 与 “1” 表⽰。

编码的实现过程很简单,只要实现哈夫曼树,通过遍历哈夫曼树,这⾥我们从根节点开始向下遍历,如果下个节点是左孩⼦,则在字符串后⾯追加 “0”,如果为其右孩⼦,则在字符串后追加 “1”。

结束条件为当前节点为叶⼦节点,得到的字符串就是叶⼦节点对应的字符的编码。

哈夫曼树实现根据贪⼼算法的思想实现,把字符出现频率较多的字符⽤稍微短⼀点的编码,⽽出现频率较少的字符⽤稍微长⼀点的编码。

哈夫曼树就是按照这种思想实现,下⾯将举例分析创建哈夫曼树的具体过程。

下⾯表格的每⼀⾏分别对应字符及出现频率,根据这些信息就能创建⼀棵哈夫曼树。

字符出现频率编码总⼆进制位数a5001500b25001500c120001360d600001240e3000001150f2000000100如下图,将每个字符看作⼀个节点,将带有频率的字符全部放到优先队列中,每次从队列中取频率最⼩的两个节点 a 和b(这⾥频率最⼩的 a 作为左⼦树),然后新建⼀个节点R,把节点设置为两个节点的频率之和,然后把这个新节点R作为节点A和B的⽗亲节点。

最后再把R放到优先队列中。

重复这个过程,直到队列中只有⼀个元素,即为哈夫曼树的根节点。

由上分析可得,哈夫曼编码的需要的总⼆进制位数为 500 + 500 + 360 + 240 + 150 + 100 = 1850。

上⾯的例⼦如果⽤等长的编码对字符进⾏压缩,实现起来更简单,6 个字符必须要 3 位⼆进制位表⽰,解压缩的时候每次从⽂本中读取 3 位⼆进制码就能翻译成对应的字符,如 000,001,010,011,100,101 分别表⽰a,b,c,d,e,f。

哈夫曼编码的应用实例

哈夫曼编码的应用实例

哈夫曼编码的应用实例引言哈夫曼编码是一种常用的数据压缩算法,它通过将出现频率较高的字符用较短的编码表示,从而实现对数据的高效压缩。

本文将通过几个实际应用实例来介绍哈夫曼编码的工作原理和应用场景。

什么是哈夫曼编码哈夫曼编码是由David A. Huffman于1952年提出的一种数据压缩算法。

它通过统计字符的出现频率,然后构建一棵二叉树,将频率较高的字符放在树的较低层,频率较低的字符放在树的较高层,从而实现对数据的压缩。

哈夫曼编码的原理1.统计字符的出现频率:首先需要统计待压缩数据中每个字符的出现频率。

2.构建哈夫曼树:根据字符的出现频率构建一棵哈夫曼树。

构建树的过程中,频率较低的字符被放在树的较高层,频率较高的字符被放在树的较低层。

3.生成哈夫曼编码:从根节点开始,沿着左子树走为0,沿着右子树走为1,将每个字符对应的编码记录下来。

4.进行编码压缩:将待压缩数据中的每个字符用其对应的哈夫曼编码替代。

5.进行解码还原:通过哈夫曼树和编码,将压缩后的数据解码还原为原始数据。

哈夫曼编码的应用实例文本文件压缩文本文件通常包含大量的字符,而且某些字符的出现频率较高。

通过使用哈夫曼编码,可以将出现频率较高的字符用较短的编码表示,从而实现对文本文件的高效压缩。

1.统计字符的出现频率:首先需要对待压缩的文本文件进行字符频率统计,得到每个字符的出现频率。

2.构建哈夫曼树:根据字符的出现频率构建一棵哈夫曼树。

3.生成哈夫曼编码:根据哈夫曼树,为每个字符生成对应的哈夫曼编码。

4.进行编码压缩:将待压缩的文本文件中的每个字符用其对应的哈夫曼编码替代。

5.进行解码还原:通过哈夫曼树和编码,将压缩后的数据解码还原为原始文本文件。

图像压缩图像文件通常包含大量的像素点,每个像素点包含多个颜色信息。

通过使用哈夫曼编码,可以将出现频率较高的颜色用较短的编码表示,从而实现对图像文件的高效压缩。

1.统计颜色的出现频率:首先需要对待压缩的图像文件进行颜色频率统计,得到每个颜色的出现频率。

利用哈夫曼编码实现压缩和解压缩

利用哈夫曼编码实现压缩和解压缩

利用哈夫曼编码实现压缩和解压缩1.问题描述利用哈夫曼编码,实现压缩和解压缩的数据元素具有如下形式:结点:weight:存储结点的权值parent:是结点双亲在向量中的下标lchild:结点的左儿子向量下标rchild:结点右儿子向量下标bits:位串,存放编码ch:字符start:编码在位串中的起始位置文件操作记录:b:记录字符在数组中的位置count:字符出现频率(权值)lch、rch、parent:定义哈夫曼树指针变量bits[256]:定义存储哈夫曼编码的数组2.功能需求对于给定的一组字符,可以根据其权值进行哈夫曼编码,并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。

能够分析文件,统计文件中出现的字符,再对文件进行编码,实现文件的压缩和解压缩,能够对于文件的压缩,比例进行统计,能够打印文件。

3.实现要点(1)构造哈弗曼树过程中,首先将初始森林的各根结点的双亲和左、右儿子指针置-1;叶子在向量T的前n个分量中,构成初始森林的n个结点;对森林中的树进行n次合并,并产生n-1个新结点,依次放入向量T的第i个分量中。

(2)编码过程中,从叶子T[i]出发,利用双亲的指针找到双亲T[p];再根据T[p]的孩子指针可以知道T[i]是T[p]的左儿子还是右儿子,若是左儿子,则生成代码0,否则生成代码1;(3)在文件压缩和解压过程中,主要参考网上资料,每个步骤都基本理解,并注上了详细解析。

4.函数定义功能:输入权重,构造一棵哈弗曼树void huffman(hftree T){if(n<1 || n > m)return;int i,j,p1,p2;float small1,small2;//初始化cout<<"请输入叶子权重(5个):"<<endl;for(i=0; i<n; i++){T[i].parent = -1;T[i].lchild = T[i].rchild = -1;}//输入叶子权值for(i=0; i<n; i++){cin>>T[i].weight;}for(i=n; i<m; i++){p1 = p2 = -1;small1 = small2 = MAX_FLOAT;for(j=0; j<=i-1; j++){if(T[j].parent != -1)continue;if(T[j].weight < small1){small2 = small1;small1 = T[j].weight;p2 = p1;p1 = j;}else if(T[j].weight < small2){small2 = T[j].weight;p2 = j;}}T[p1].parent = T[p2].parent = i;T[i].parent=-1;T[i].lchild=p1;T[i].rchild=p2;T[i].weight=small1 + small2;}cout<<"创建成功!"<<endl;}功能:对哈弗曼树进行编码void encode(codelist codes, hftree T){int i,c,p,start;cout<<"请输入需要编码的字符(5个):"<<endl;for(i=0; i<n; i++){cin>>codes[i].ch;start=n;c=i;p=T[i].parent;while(p!=-1){start--;if(T[p].lchild==c) codes[i].bits[start]='0';else codes[i].bits[start]='1';c=p;p=T[p].parent;}codes[i].start=start;}cout<<"输入成功!:"<<endl;cout<<"编码表:"<<endl;for(int x=0; x<n; x++){cout<<codes[x].ch<<": ";for(int q=codes[x].start;q<n;q++) cout<<codes[x].bits[q];cout<<endl;}}函数功能:对哈弗曼树进行解码void decode(codelist codes,hftree T){int i,c,p,b;int endflag;endflag=-1;i=m-1;while(cin>>b,b!=endflag){if(b==0) i=T[i].lchild;else i=T[i].rchild;if(T[i].lchild==-1){cout<<codes[i].ch;i=m-1;}}if(i!=m-1)cout<<"编码有错!\n"; }功能:对文件进行压缩,统计压缩率void compress(){char filename[255],outputfile[255],buf[512];unsigned char c;long i,j,m,n,f;long min1,pt1,flength,length1,length2; double div;FILE *ifp,*ofp;cout<<"\t请您输入需要压缩的文件:";cin>>filename;ifp=fopen(filename,"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n\n";return;}cout<<"\t请您输入压缩后的文件名:";cin>>outputfile;ofp=fopen(strcat(outputfile,".encode"),"wb");if(ofp==NULL){cout<<"\n\t压缩文件失败!\n\n";return;}flength=0;while(!feof(ifp)){fread(&c,1,1,ifp);header[c].count++; //字符重复出现频率+1flength++; //字符出现原文件长度+1 }flength--;length1=flength; //原文件长度用作求压缩率的分母header[c].count--;for(i=0;i<512;i++){if(header[i].count!=0) header[i].b=(unsigned char)i;else header[i].b=0;header[i].parent=-1;header[i].lch=header[i].rch=-1; //对结点进行初始化}for(i=0;i<256;i++) //根据频率(权值)大小,对结点进行排序,选择较小的结点进树{for(j=i+1;j<256;j++){if(header[i].count<header[j].count){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}for(i=0;i<256;i++) if(header[i].count==0) break;n=i; //外部叶子结点数为n个时,部结点数为n-1,整个哈夫曼树的需要的结点数为2*n-1.m=2*n-1;for(i=n;i<m;i++) //构建哈夫曼树{min1=999999999; //预设的最大权值,即结点出现的最大次数for(j=0;j<i;j++){if(header[j].parent!=-1) continue;//parent!=-1说明该结点已存在哈夫曼树中,跳出循环重新选择新结点*/if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count=header[pt1].count;header[pt1].parent=i; //依据parent域值(结点层数)确定树中结点之间的关系header[i].lch=pt1; //计算左分支权值大小min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1) continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count+=header[pt1].count;header[i].rch=pt1; //计算右分支权值大小header[pt1].parent=i;}for(i=0;i<n;i++) //哈夫曼无重复前缀编码{f=i;header[i].bits[0]=0; //根结点编码0while(header[f].parent!=-1){j=f;f=header[f].parent;if(header[f].lch==j) //置左分支编码0{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);//依次存储连接“0”“1”编码header[i].bits[0]='0';}else //置右分支编码1{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='1';}}}fseek(ifp,0,SEEK_SET); //从文件开始位置向前移动0字节,即定位到文件开始位置fwrite(&flength,sizeof(int),1,ofp);fseek(ofp,8,SEEK_SET);buf[0]=0; //定义缓冲区,它的二进制表示00000000f=0;pt1=8;while(!feof(ifp)){c=fgetc(ifp);f++;for(i=0;i<n;i++){if(c==header[i].b) break;strcat(buf,header[i].bits);j=strlen(buf);c=0;while(j>=8) //对哈夫曼编码位操作进行压缩存储{for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++; //统计压缩后文件的长度strcpy(buf,buf+8); //一个字节一个字节拼接j=strlen(buf);}if(f==flength) break;}if(j>0) //对哈夫曼编码位操作进行压缩存储{strcat(buf,"00000000");for(i=0;i<8;i++)if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;}fseek(ofp,4,SEEK_SET);fwrite(&pt1,sizeof(long),1,ofp);fseek(ofp,pt1,SEEK_SET);fwrite(&n,sizeof(long),1,ofp);for(i=0;i<n;i++){fwrite(&(header[i].b),1,1,ofp);c=strlen(header[i].bits);fwrite(&c,1,1,ofp);j=strlen(header[i].bits);if(j%8!=0) //若存储的位数不是8的倍数,则补0 {for(f=j%8;f<8;f++)strcat(header[i].bits,"0");}while(header[i].bits[0]!=0){c=0;for(j=0;j<8;j++) //字符的有效存储不超过8位,则对有效位数左移实现两字符编码的连接{if(header[i].bits[j]=='1') c=(c<<1)|1; //|1不改变原位置上的“0”“1”值else c=c<<1;}strcpy(header[i].bits,header[i].bits+8); //把字符的编码按原先存储顺序连接fwrite(&c,1,1,ofp);}}length2=pt1--;div=((double)length1-(double)length2)/(double)length1; //计算文件的压缩率fclose(ifp);fclose(ofp);printf("\n\t压缩文件成功!\n");printf("\t压缩率为%f%%\n\n",div*100);return;}函数功能:对文件解压缩void uncompress(){char filename[255],outputfile[255],buf[255],bx[255];unsigned char c;long i,j,m,n,f,p,l;long flength;FILE *ifp,*ofp;cout<<"\t请您输入需要解压缩的文件:";cin>>filename;ifp=fopen(strcat(filename,".encode"),"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n";return;}cout<<"\t请您输入解压缩后的文件名:";cin>>outputfile;ofp=fopen(outputfile,"wb");if(ofp==NULL){cout<<"\n\t解压缩文件失败!\n";return;}fread(&flength,sizeof(long),1,ifp); //读取原文件长度,对文件进行定位fread(&f,sizeof(long),1,ifp);fseek(ifp,f,SEEK_SET);fread(&n,sizeof(long),1,ifp);for(i=0;i<n;i++){fread(&header[i].b,1,1,ifp);fread(&c,1,1,ifp);p=(long)c; //读取原文件字符的权值header[i].count=p;header[i].bits[0]=0;if(p%8>0) m=p/8+1;else m=p/8;for(j=0;j<m;j++){fread(&c,1,1,ifp);f=c;itoa(f,buf,2); //将f转换为二进制表示的字符串f=strlen(buf);for(l=8;l>f;l--){strcat(header[i].bits,"0");}strcat(header[i].bits,buf);}header[i].bits[p]=0;}for(i=0;i<n;i++) //根据哈夫曼编码的长短,对结点进行排序{for(j=i+1;j<n;j++){if(strlen(header[i].bits)>strlen(header[j].bits)){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}p=strlen(header[n-1].bits);fseek(ifp,8,SEEK_SET);m=0;bx[0]=0;while(1) //通过哈夫曼编码的长短,依次解码,从原来的位存储还原到字节存储{while(strlen(bx)<(unsigned int)p){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--) //在单字节对相应位置补0{strcat(bx,"0");}strcat(bx,buf);}for(i=0;i<n;i++){if(memcmp(header[i].bits,bx,header[i].count)==0) break;}strcpy(bx,bx+header[i].count);c=header[i].b;fwrite(&c,1,1,ofp);m++; //统计解压缩后文件的长度if(m==flength) break; //flength是原文件长度}fclose(ifp);fclose(ofp);cout<<"\n\t解压缩文件成功!\n";if(m==flength) //对解压缩后文件和原文件相同性比较进行判断(根据文件大小)cout<<"\t解压缩文件与原文件相同!\n\n";else cout<<"\t解压缩文件与原文件不同!\n\n";return;}5、总结和体会本次大作业与C++大作业有所不同,主要是利用构造数据结构解决问题,C++大作业主要体现类和文件读写功能。

利用哈夫曼编码实现压缩和解压缩

利用哈夫曼编码实现压缩和解压缩

利用哈夫曼编码实现压缩和解压缩1.问题描述利用哈夫曼编码,实现压缩和解压缩的数据元素具有如下形式:结点:weight:存储结点的权值parent:是结点双亲在向量中的下标lchild:结点的左儿子向量下标rchild:结点右儿子向量下标bits:位串,存放编码ch:字符start:编码在位串中的起始位置文件操作记录:b:记录字符在数组中的位置count:字符出现频率(权值)lch、rch、parent:定义哈夫曼树指针变量bits[256]:定义存储哈夫曼编码的数组2.功能需求对于给定的一组字符,可以根据其权值进行哈夫曼编码,并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。

能够分析文件,统计文件中出现的字符,再对文件进行编码,实现文件的压缩和解压缩,能够对于文件的压缩,比例进行统计,能够打印文件。

3.实现要点(1)构造哈弗曼树过程中,首先将初始森林的各根结点的双亲和左、右儿子指针置-1;叶子在向量T的前n个分量中,构成初始森林的n个结点;对森林中的树进行n次合并,并产生n-1个新结点,依次放入向量T的第i个分量中。

(2)编码过程中,从叶子T[i]出发,利用双亲的指针找到双亲T[p];再根据T[p]的孩子指针可以知道T[i]是T[p]的左儿子还是右儿子,若是左儿子,则生成代码0,否则生成代码1;(3)在文件压缩和解压过程中,主要参考网上资料,每个步骤都基本理解,并注上了详细解析。

4.函数定义功能:输入权重,构造一棵哈弗曼树void huffman(hftree T){if(n<1 || n > m)return;int i,j,p1,p2;float small1,small2;//初始化cout<<"请输入叶子权重(5个):"<<endl;for(i=0; i<n; i++){T[i].parent = -1;T[i].lchild = T[i].rchild = -1;}//输入叶子权值for(i=0; i<n; i++){cin>>T[i].weight;}for(i=n; i<m; i++){p1 = p2 = -1;small1 = small2 = MAX_FLOAT;for(j=0; j<=i-1; j++){if(T[j].parent != -1)continue;if(T[j].weight < small1){small2 = small1;small1 = T[j].weight;p2 = p1;p1 = j;}else if(T[j].weight < small2){small2 = T[j].weight;p2 = j;}}T[p1].parent = T[p2].parent = i;T[i].parent=-1;T[i].lchild=p1;T[i].rchild=p2;T[i].weight=small1 + small2;}cout<<"创建成功!"<<endl;}功能:对哈弗曼树进行编码void encode(codelist codes, hftree T){int i,c,p,start;cout<<"请输入需要编码的字符(5个):"<<endl;for(i=0; i<n; i++){cin>>codes[i].ch;start=n;c=i;p=T[i].parent;while(p!=-1){start--;if(T[p].lchild==c) codes[i].bits[start]='0';else codes[i].bits[start]='1';c=p;p=T[p].parent;}codes[i].start=start;}cout<<"输入成功!:"<<endl;cout<<"编码表:"<<endl;for(int x=0; x<n; x++){cout<<codes[x].ch<<": ";for(int q=codes[x].start;q<n;q++) cout<<codes[x].bits[q];cout<<endl;}}函数功能:对哈弗曼树进行解码void decode(codelist codes,hftree T) {int i,c,p,b;int endflag;endflag=-1;i=m-1;while(cin>>b,b!=endflag){if(b==0) i=T[i].lchild;else i=T[i].rchild;if(T[i].lchild==-1){cout<<codes[i].ch;i=m-1;}}if(i!=m-1)cout<<"编码有错!\n";}功能:对文件进行压缩,统计压缩率void compress(){char filename[255],outputfile[255],buf[512];unsigned char c;long i,j,m,n,f;long min1,pt1,flength,length1,length2;double div;FILE *ifp,*ofp;cout<<"\t请您输入需要压缩的文件:";cin>>filename;ifp=fopen(filename,"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n\n";return;}cout<<"\t请您输入压缩后的文件名:";cin>>outputfile;ofp=fopen(strcat(outputfile,".encode"),"wb");if(ofp==NULL){cout<<"\n\t压缩文件失败!\n\n";return;}flength=0;while(!feof(ifp)){fread(&c,1,1,ifp);header[c].count++; //字符重复出现频率+1flength++; //字符出现原文件长度+1}flength--;length1=flength; //原文件长度用作求压缩率的分母header[c].count--;for(i=0;i<512;i++){if(header[i].count!=0) header[i].b=(unsigned char)i;else header[i].b=0;header[i].parent=-1;header[i].lch=header[i].rch=-1; //对结点进行初始化}for(i=0;i<256;i++) //根据频率(权值)大小,对结点进行排序,选择较小的结点进树{for(j=i+1;j<256;j++){if(header[i].count<header[j].count){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}for(i=0;i<256;i++) if(header[i].count==0) break;n=i; //外部叶子结点数为n个时,内部结点数为n-1,整个哈夫曼树的需要的结点数为2*n-1.m=2*n-1;for(i=n;i<m;i++) //构建哈夫曼树{min1=999999999; //预设的最大权值,即结点出现的最大次数for(j=0;j<i;j++){if(header[j].parent!=-1) continue;//parent!=-1说明该结点已存在哈夫曼树中,跳出循环重新选择新结点*/if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count=header[pt1].count;header[pt1].parent=i; //依据parent域值(结点层数)确定树中结点之间的关系header[i].lch=pt1; //计算左分支权值大小min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1) continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count+=header[pt1].count;header[i].rch=pt1; //计算右分支权值大小header[pt1].parent=i;}for(i=0;i<n;i++) //哈夫曼无重复前缀编码{f=i;header[i].bits[0]=0; //根结点编码0while(header[f].parent!=-1){j=f;f=header[f].parent;if(header[f].lch==j) //置左分支编码0{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);//依次存储连接“0”“1”编码header[i].bits[0]='0';}else //置右分支编码1{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='1';}}}fseek(ifp,0,SEEK_SET); //从文件开始位置向前移动0字节,即定位到文件开始位置fwrite(&flength,sizeof(int),1,ofp);fseek(ofp,8,SEEK_SET);buf[0]=0; //定义缓冲区,它的二进制表示00000000f=0;pt1=8;while(!feof(ifp)){c=fgetc(ifp);f++;for(i=0;i<n;i++){if(c==header[i].b) break;}strcat(buf,header[i].bits);j=strlen(buf);c=0;while(j>=8) //对哈夫曼编码位操作进行压缩存储{for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++; //统计压缩后文件的长度strcpy(buf,buf+8); //一个字节一个字节拼接j=strlen(buf);}if(f==flength) break;}if(j>0) //对哈夫曼编码位操作进行压缩存储{strcat(buf,"00000000");for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;}fseek(ofp,4,SEEK_SET);fwrite(&pt1,sizeof(long),1,ofp);fseek(ofp,pt1,SEEK_SET);fwrite(&n,sizeof(long),1,ofp);for(i=0;i<n;i++){fwrite(&(header[i].b),1,1,ofp);c=strlen(header[i].bits);fwrite(&c,1,1,ofp);j=strlen(header[i].bits);if(j%8!=0) //若存储的位数不是8的倍数,则补0 {for(f=j%8;f<8;f++)strcat(header[i].bits,"0");}while(header[i].bits[0]!=0){c=0;for(j=0;j<8;j++) //字符的有效存储不超过8位,则对有效位数左移实现两字符编码的连接{if(header[i].bits[j]=='1') c=(c<<1)|1; //|1不改变原位置上的“0”“1”值else c=c<<1;}strcpy(header[i].bits,header[i].bits+8); //把字符的编码按原先存储顺序连接fwrite(&c,1,1,ofp);}}length2=pt1--;div=((double)length1-(double)length2)/(double)length1; //计算文件的压缩率fclose(ifp);fclose(ofp);printf("\n\t压缩文件成功!\n");printf("\t压缩率为 %f%%\n\n",div*100);return;}函数功能:对文件解压缩void uncompress(){char filename[255],outputfile[255],buf[255],bx[255];unsigned char c;long i,j,m,n,f,p,l;long flength;FILE *ifp,*ofp;cout<<"\t请您输入需要解压缩的文件:";cin>>filename;ifp=fopen(strcat(filename,".encode"),"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n";return;}cout<<"\t请您输入解压缩后的文件名:";cin>>outputfile;ofp=fopen(outputfile,"wb");if(ofp==NULL){cout<<"\n\t解压缩文件失败!\n";return;}fread(&flength,sizeof(long),1,ifp); //读取原文件长度,对文件进行定位fread(&f,sizeof(long),1,ifp);fseek(ifp,f,SEEK_SET);fread(&n,sizeof(long),1,ifp);for(i=0;i<n;i++){fread(&header[i].b,1,1,ifp);fread(&c,1,1,ifp);p=(long)c; //读取原文件字符的权值header[i].count=p;header[i].bits[0]=0;if(p%8>0) m=p/8+1;else m=p/8;for(j=0;j<m;j++){fread(&c,1,1,ifp);f=c;itoa(f,buf,2); //将f转换为二进制表示的字符串f=strlen(buf);for(l=8;l>f;l--){strcat(header[i].bits,"0");}strcat(header[i].bits,buf);}header[i].bits[p]=0;}for(i=0;i<n;i++) //根据哈夫曼编码的长短,对结点进行排序{for(j=i+1;j<n;j++){if(strlen(header[i].bits)>strlen(header[j].bits)){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}p=strlen(header[n-1].bits);fseek(ifp,8,SEEK_SET);m=0;bx[0]=0;while(1) //通过哈夫曼编码的长短,依次解码,从原来的位存储还原到字节存储{while(strlen(bx)<(unsigned int)p){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--) //在单字节内对相应位置补0{strcat(bx,"0");}strcat(bx,buf);}for(i=0;i<n;i++){if(memcmp(header[i].bits,bx,header[i].count)==0) break;}strcpy(bx,bx+header[i].count);c=header[i].b;fwrite(&c,1,1,ofp);m++; //统计解压缩后文件的长度if(m==flength) break; //flength是原文件长度}fclose(ifp);fclose(ofp);cout<<"\n\t解压缩文件成功!\n";if(m==flength) //对解压缩后文件和原文件相同性比较进行判断(根据文件大小)cout<<"\t解压缩文件与原文件相同!\n\n";else cout<<"\t解压缩文件与原文件不同!\n\n";return;}5、总结和体会本次大作业与C++大作业有所不同,主要是利用构造数据结构解决问题,C++大作业主要体现类和文件读写功能。

C语言中的数据压缩与解压缩

C语言中的数据压缩与解压缩

C语言中的数据压缩与解压缩在计算机科学中,数据压缩是一种常见的技术,用于将大型数据文件或数据流以更小的尺寸存储或传输。

在C语言中,我们可以使用各种算法和技术来实现数据的压缩和解压缩。

本文将详细介绍C语言中常用的数据压缩与解压缩方法。

一、哈夫曼编码1.1 简介哈夫曼编码是一种无损压缩算法,由数学家David A. Huffman于1952年提出。

它根据数据中字符出现的频率来构建一个具有最小编码长度的前缀码。

在C语言中,我们可以使用哈夫曼编码来进行数据的压缩和解压缩。

1.2 压缩过程哈夫曼编码的压缩过程分为以下几个步骤:a) 统计数据中各字符的频率,构建字符频率表。

b) 根据字符频率表构建哈夫曼树。

c) 根据哈夫曼树构建字符编码表。

d) 遍历数据,使用字符编码表将字符转换为对应的编码,并将编码存储。

1.3 解压缩过程哈夫曼编码的解压缩过程分为以下几个步骤:a) 使用压缩时生成的字符编码表,将压缩后的编码转换为对应的字符。

b) 将解压后的字符恢复为原始数据。

二、LZ77压缩算法2.1 简介LZ77是一种常用的数据压缩算法,由Abraham Lempel和Jacob Ziv 于1977年提出。

它利用了数据中的重复出现模式,通过记录重复出现的字符串的位置和长度来实现数据的压缩。

2.2 压缩过程LZ77压缩算法的压缩过程分为以下几个步骤:a) 初始化一个滑动窗口,窗口大小为固定长度。

b) 在滑动窗口内查找与当前字符匹配的最长字符串,并记录字符串的位置和长度。

c) 将匹配的字符串以位置和长度的形式存储,并将窗口向右滑动到匹配字符串的末尾。

d) 重复步骤b和c,直到遍历完所有数据。

2.3 解压缩过程LZ77压缩算法的解压缩过程分为以下几个步骤:a) 根据压缩时存储的位置和长度信息,从滑动窗口中找到对应的字符串。

b) 将找到的字符串输出,并将窗口向右滑动到输出字符串的末尾。

c) 重复步骤a和b,直到解压缩完成。

三、LZ78压缩算法3.1 简介LZ78是一种常用的数据压缩算法,由Abraham Lempel和Jacob Ziv 于1978年提出。

哈夫曼编码 压缩

哈夫曼编码 压缩

哈夫曼编码压缩标题:哈夫曼编码压缩:一个深度解析一、引言哈夫曼编码是一种用于数据压缩的算法,由戴维·A·哈夫曼在1952年提出。

这种编码方法通过创建一种特殊的二叉树(哈夫曼树)来实现数据压缩。

哈夫曼编码广泛应用于文本文件、音频文件、图像文件等的数据压缩。

二、哈夫曼树的构建哈夫曼树是一种特殊的二叉树,它的特点是左子节点小于父节点,右子节点大于父节点。

哈夫曼树的构建过程如下:1. 初始化:将所有字符及其出现频率作为叶子节点,构成一棵棵只有根节点和一个叶子节点的二叉树。

2. 合并:每次选取两个权值最小的节点,生成一个新的节点,新节点的权值是两个被选取节点权值之和,然后把这两个节点作为新节点的左右孩子。

这样就得到了一颗新的二叉树。

3. 重复第二步,直到只剩下一个节点,这棵树就是我们要找的哈夫曼树。

三、哈夫曼编码哈夫曼编码是指从哈夫曼树的根到每个叶子节点的路径上的0和1的序列。

具体做法是从根节点出发,向左走记为0,向右走记为1。

每个字符的哈夫曼编码就是从根节点到该字符所在叶子节点的路径上的0和1的序列。

四、哈夫曼编码的压缩与解压1. 压缩:对原始数据进行哈夫曼编码,得到压缩后的数据。

2. 解压:对压缩后的数据进行哈夫曼解码,还原出原始数据。

五、哈夫曼编码的优点与缺点优点:1. 数据压缩效率高:哈夫曼编码能够有效地减少数据存储空间,提高数据传输速度。

2. 简单易懂:哈夫曼编码的原理和实现都比较简单,易于理解和实现。

缺点:1. 对于稀疏数据,压缩效果不佳:哈夫曼编码依赖于字符的出现频率,如果字符出现频率相近,压缩效果会降低。

2. 需要额外的存储空间:为了恢复原始数据,需要保存哈夫曼树或者哈夫曼编码表,这会占用一定的存储空间。

六、总结哈夫曼编码是一种有效的数据压缩方法,它通过构建哈夫曼树来实现数据的压缩和解压。

虽然哈夫曼编码有一些缺点,但其高效性和简单性使其在实际应用中得到了广泛的应用。

在未来,随着数据量的不断增大,哈夫曼编码等数据压缩技术将会发挥更大的作用。

哈夫曼编码算法的原理及应用

哈夫曼编码算法的原理及应用

哈夫曼编码算法的原理及应用随着信息技术的快速发展和数字化时代的到来,数据量的增加、存储和传输的要求也愈加严格。

如何用最少的存储空间传输最多的信息,成为了数字化时代数据处理的重要问题。

哈夫曼编码算法由于它对数据的高效压缩和快速解压,已经成为信息技术领域中常用的压缩算法之一。

一、哈夫曼编码算法的原理哈夫曼编码算法是由美国数学家哈夫曼在1952年发明的一种高效的数据压缩算法,它是一种前缀编码方式,利用不同字符出现的频率不同,将频率小的字符用较短的编码表达,频率大的字符则用较长的编码表示。

在编码表中,任何一个字符的编码都不会是另一个的编码的前缀,这就是哈夫曼编码的前缀编码优势。

采用哈夫曼编码算法最终压缩得到的数据是无损的,因为压缩后的数据是通过编码表进行翻译的,不会出现错误的情况。

哈夫曼编码算法的实现包括两个主要步骤:创建哈夫曼树和生成哈夫曼编码。

创建哈夫曼树:哈夫曼树是由哈夫曼算法创建的,其基本思想是将每个字符看作一棵树,以该字符出现的频率为权值,进行递归合并,直到所有的树合并为一棵哈夫曼树。

哈夫曼树的结构可以用一棵二叉树来表示,每个节点代表一个字符或者一个由多个字符组成的字符串。

生成哈夫曼编码:通过哈夫曼树可以生成哈夫曼编码表,哈夫曼编码表可以用一个映射关系来表示,将每个字符与对应的编码对应起来。

在哈夫曼树的遍历过程中,当向左走时,添加0到编码中,向右走时,添加1到编码中,直到到达叶子节点时,记录下该字符的哈夫曼编码。

二、哈夫曼编码算法的应用哈夫曼编码算法的应用非常广泛,除了在数据压缩中广泛应用外,它在通信、数据存储等领域也有很多应用。

下面我们介绍几个典型的应用场景。

1. 压缩和解压缩作为一种高效的数据压缩算法,哈夫曼编码算法被广泛应用于文件和图像等数据的压缩和解压缩中。

哈夫曼编码通过对数据进行更高效的压缩,可以节约存储空间和传输带宽。

在压缩文件的过程中,压缩后的文件大小通常能缩小到原来的50%以下。

哈夫曼编码的压缩与解压缩

哈夫曼编码的压缩与解压缩

哈夫曼编码的压缩与解压缩1.引言1.1 概述哈夫曼编码是一种常用的数据压缩算法,它采用了一种变长编码方式,将出现频率高的字符用较短的编码表示,出现频率低的字符用较长的编码表示,以达到压缩数据的目的。

该编码方法由美国数学家大卫·哈夫曼于1952年提出,被广泛应用于各种数据压缩和传输领域。

在传统的固定长度编码中,每个字符都使用相同的位数来表示,因此在表示不同概率出现的字符时,可能会浪费大量的位数。

而哈夫曼编码则是根据字符在文本中出现的频率来确定其对应的编码,使得高频出现的字符用更短的编码表示,低频出现的字符用较长的编码表示。

哈夫曼编码的核心思想是构建一棵哈夫曼树,将出现频率作为权值,频率越高的字符离根节点越近。

通过从叶子节点到根节点的路径确定每个字符的编码,即将左子树标记为0,右子树标记为1。

在对文本进行压缩时,将文本中的字符转换为其对应的哈夫曼编码,即可将原始数据压缩为较短的二进制串。

相比于传统固定长度编码,哈夫曼编码具有显著的优势。

首先,它可以根据文本中字符出现的实际情况进行编码,使得频率高的字符用较短的编码表示,从而大幅度减少了编码后的数据长度。

其次,哈夫曼编码是一种前缀编码,即任何一个字符的编码都不是其他字符编码的前缀,这样在解码时可以直接根据编码找到对应的字符,无需回溯查表,提高了解码效率。

哈夫曼编码的应用广泛,它被用于无损图像压缩、音频压缩、文本压缩等领域。

随着互联网和大数据时代的到来,数据的传输和存储成为重要的问题,如何高效地压缩和解压缩数据成为一个热门的研究方向。

哈夫曼编码作为一种简单而有效的压缩算法,具有广阔的应用前景。

然而,哈夫曼编码也存在一些问题,如编码时需要构建哈夫曼树,需要额外的空间和时间开销,对于小规模数据可能会影响压缩效率。

因此,在实际应用中,需要综合考虑数据规模和应用场景,选择合适的压缩算法。

1.2 文章结构本文主要介绍了哈夫曼编码的压缩与解压缩。

文章分为引言、正文和结论三个部分。

哈夫曼的文件压缩解压程序课件

哈夫曼的文件压缩解压程序课件
为了提高哈夫曼压缩算法的性能和压缩比,可以采用以 下优化措施
对数据进行预处理,例如去除冗余信息、进行数据格式 化等,以减少需要压缩的数据量。
使用更高效的编码和解码算法,例如使用位操作代替字 符串操作,减少内存占用和计算时间。
采用动态哈夫曼编码技术,根据数据流的特点动态调整 哈夫曼树的结构,以实现更好的压缩效果。
文件压缩原理
文件压缩的概念
01
02
03
文件压缩
通过特定的算法对文件进 行编码,以减少其存储空 间的需求,同时保持文件 完整性和可读性。
压缩文件
经过压缩处理后的文件, 其大小明显小于原始文件 。
解压缩
将压缩文件还原为原始大 小的过程。
文件压缩的原理
数据冗余
大多数文件都包含大量的 数据冗余,如重复的模式 或数据块。
编码
利用数据冗余,通过特定 的算法对数据进行编码, 以减少存储空间需求。
熵编码
根据数据的概率分布进行 编码,使常见数据使用较 短的编码,罕见数据使用 较长的编码。
常见文件压缩算法
Huffman编码
Bzip2
一种基于熵编码的算法,根据数据的 概率分布创建字符到二进制码的映射 。
使用Burrows-Wheeler变换和 Huffman编码的压缩算法,具有较高 的压缩比和较好的数据完整性。
因素。
06
哈夫曼压缩解压程序应用 实例
哈夫曼压缩解压程序的使用场景
1 2
数据存储
哈夫曼压缩解压程序常用于数据存储领域,能够 有效地减小数据文件的大小,节省存储空间。
网络传输
在网络传输中,哈夫曼压缩解压程序能够降低传 输时间和带宽消耗,提高传输效率。
3
实时处理

哈夫曼算法进行文件压缩和解压缩

哈夫曼算法进行文件压缩和解压缩

本文首先简要阐述哈夫曼算法的基本思想,然后介绍了使用哈夫曼算法进行文件压缩和解压缩的处理步骤,最后给出了C语言实现的文件压缩和解压缩的源代码。

哈夫曼算法的主要思想是:①首先遍历要处理的字符串,得到每个字符的出现的次数;②将每个字符(以其出现次数为权值)分别构造为二叉树(注意此时的二叉树只有一个节点);③取所有二叉树种种字符出现次数最小的二叉树合并为一颗新的二叉树,新二叉树根节点的权值等于两个子节点的权值之和,新节点中的字符忽略;④重复过程③直到所有树被合并为同一棵二叉树⑤遍历最后得到的二叉树,自顶向下按路径编号,指向左节点的边编号0,指向右节点的边编号1,从根到叶节点的所有边上的0和1链接起来,就是叶子节点中字符的哈夫曼编码。

下图展示了哈夫曼编码的基本思想。

基于哈夫曼算法的文件压缩和解压缩过程分别说明如下:一、文件压缩:①统计词频:读取文件的每个字节,使用整数数组int statistic[MAX_CHARS]统计每个字符出现的次数,由于一个字节最多表示2^8-1个字符,所以MAX_CHARS=256就足够了。

在统计字符数的时候,对于每一个byte, 有statistic[(unsigned char)byte]++。

②构造哈夫曼树:根据statistic数组,基于哈夫曼树算法造哈夫曼树,由于构造的过程中每次都要取最小权值的字符,所以需要用优先队列来维护每棵树的根节点。

③生成编码:深度优先遍历哈弗曼树,得到每个叶子节点中的字符的编码并存入字符串数组char *dictionary[MAX_CHARS];④存储词频:新建存储压缩数据的文件,首先写入不同字符的个数,然后将每个字符及其对应的词频写入文件。

⑤存储压缩数据:再次读取待压缩文件的每个字节byte,由dictionary[(unsigned int)byte]得到对应的编码(注意每个字符编码的长度不一),使用位运算一次将编码中的每个位(BIT)设置到一个char 类型的位缓冲中,可能多个编码才能填满一个位缓冲,每填满一次,将位缓冲区以单个字节的形式写入文件。

使用huffman编码压缩与解压缩(python)

使用huffman编码压缩与解压缩(python)

使⽤huffman编码压缩与解压缩(python)⼀、huffman 编码1.1 huffman 编码介绍哈夫曼编码(Huffman Coding),⼜称霍夫曼编码,是⼀种编码⽅式,哈夫曼编码是可变字长编码(VLC)的⼀种。

Huffman于1952年提出⼀种编码⽅法,该⽅法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,⼀般就叫做Huffman编码(有时也称为霍夫曼编码)huffman 编码是最优码,也是即时码(证明较为复杂,在此不给出证明)1.2 huffman 编码此处介绍⼆元 huffman 编码给定⼀个字符集合 S={s0,s1,⋯,s q},每个字符的概率为 P={p0,p1,⋯,p q}将字符集合按概率由⼤到⼩重新排列,即使得p i≥p i+1将最末尾的两个字符s q−1和s q合并,记为s′,s′的概率为p′=p q−1+p q如果剩余的字符数不为 1,则回到第 1 步huffman 编码的过程⼤致就上述三步当编码完毕后,会构建出⼀棵码树,每个码字的编码可以从码树中获得举个简单的例⼦,对于字符集合 S={A,B,C},概率为 P=0.5,0.3,0.2将B,C合并,记为BC,p(BC)=p(B)+p(C)=0.3+0.2=0.5然后将A,BC合并,记为ABC,p(ABC)=p(A)+p(BC)=0.5+0.5=1记根节点 ABC 码字为空,从根节点向下遍历,往左⾛码字末尾添0,往右⾛添1,那么 A, B, C 的码字分别为 0, 10, 11,编码表就是 {A:0,B:10,C:11}1.3 huffman 编程实现见后⽂的代码实现1.4 测试⾸先在代码⽬录下新建⼀个newfile.txt,⾥边写⼊ABCDEFG下⾯的代码实现了读取newfile.txt并对其压缩,将结果输出⾄output.enc然后对output.enc进⾏解压缩,将解压缩结果输出⾄output.dec# 读⼊⽂件with open('newfile.txt', 'rb') as fp_in:str_bytes = fp_in.read()# 构建huffman编码fre_dic = bytes_fre(str_bytes)huffman_dic = build(fre_dic)# 对⽂本进⾏编码str_enc, padding = encode(str_bytes, huffman_dic, False)# 输出⾄⽂件 output.encwith open('output.enc', 'wb') as fp_out:fp_out.write(str_enc)# 对编码后的⽂本进⾏解码str_dec = decode(str_enc, huffman_dic, padding, False)# 输出⾄⽂件 output.decwith open('output.dec', 'wb') as fp_out:fp_out.write(str_dec)# 打印huffman字典和填充位print('huffman_dic:', huffman_dic)print('padding:', padding)观察压缩前和压缩后的⽂件,发现经过我们的程序压缩之后,⽂件⼩了很多使⽤ winhex 打开 newfile.txt, output.enc, output.dec 查看对应的⼗六进制数值观察 newfile.txt 和 output.dec 的⼗六进制数值,发现⼀模⼀样,说明我们的压缩和解压并没有问题,程序正确接下来来分析 output.enc ⽂件的内容output.enc 中的数值为 C1 4E 50,转化成⼆进制为 11000001 01001110 01010000Loading [MathJax]/jax/output/HTML-CSS/jax.js我们将中间构造出的编码表打印出来,可以得到编码表字符A B C D E F G编码11000001010011100101以及填充位 padding 的值为 4我们对 newfile.txt 中的字符 ABCDEFG 进⾏编码,结果为 11 000 001 010 011 100 101。

哈夫曼压缩类-概述说明以及解释

哈夫曼压缩类-概述说明以及解释

哈夫曼压缩类-概述说明以及解释1.引言1.1 概述哈夫曼压缩是一种常用的数据压缩算法,旨在通过减少数据的冗余性,以降低数据的存储空间和传输成本。

这种压缩方法是由大卫·哈夫曼(David A. Huffman)于1952年提出的,并因此被命名为哈夫曼压缩。

概括地说,哈夫曼压缩通过对数据中经常出现的字符或字符组合进行编码,将其替换为更短的二进制码来实现压缩。

这种编码方案是基于字符频率统计的结果,即出现频率较高的字符被赋予较短的编码,而较少出现的字符则被分配较长的编码。

由于频率较高的字符占用的二进制位数较少,这种编码方式可以有效减少数据的存储空间。

哈夫曼编码的实现过程包括两个主要步骤:字符频率统计和编码生成。

在字符频率统计阶段,系统会对给定的数据进行遍历,记录每个字符出现的频率。

然后,在编码生成阶段,根据字符的频率构建哈夫曼树,并使用哈夫曼树生成每个字符对应的编码。

通过这种方式,我们能够生成一个唯一且无二义性的编码表,将每个字符映射到其对应的编码。

哈夫曼压缩在许多场景中有着广泛的应用。

例如,在文件压缩方面,哈夫曼压缩已成为诸多压缩文件格式的基础算法,比如ZIP和GZIP。

此外,哈夫曼压缩也被广泛应用于图像、音频和视频压缩领域,能够在不损失重要信息的前提下,显著减小文件的大小,提高传输速度和存储效率。

尽管哈夫曼压缩在各种应用中取得了显著效果,但仍存在一些局限性。

例如,压缩率的提升受限于数据的冗余度。

在数据中存在较少重复字符或字符组合的情况下,哈夫曼压缩的效果可能不如其他更为复杂的压缩算法。

此外,哈夫曼编码的生成过程需要额外的时间和计算资源,因此在某些场景下,对实时性要求较高的数据可能不适合使用哈夫曼压缩。

综上所述,哈夫曼压缩作为一种常用而有效的数据压缩方法,在各种应用场景中都有其独特的优势和不足。

在未来,随着数据量的不断增长和对存储空间和传输速度的需求增加,我们可以进一步研究和改进哈夫曼压缩算法,以提高其压缩率和性能,并在更广泛的领域中得到应用。

信息论编码课程设计(用哈夫曼编码实现一个完整的压缩与解压程序)

信息论编码课程设计(用哈夫曼编码实现一个完整的压缩与解压程序)

课程设计任务书2011—2012学年第二学期专业:信息与计算科学学号:姓名:课程设计名称:信息论与编码课程设计设计题目:用哈夫曼编码实现一个完整的压缩与解压程序完成期限:自年月日至年月日共天一.设计目的1、深刻理解信源编码的基本思想与目的;2、理解哈夫曼编码方法的基本过程与特点;3、详细地理解文件的压缩与解压过程;4、提高综合运用所学理论知识独立分析和解决问题的能力;5、使用C语言进行编程。

二.设计内容假设已知一个文件内部所有的字符,编写适当函数,对其进行哈夫曼编码的编译,同时将其运用位操作进行压缩与解压,并且由其文件内字符长度的压缩和气原本长度进行计算,从而得出压缩率的大小。

三.设计要求1、编写的函数要有通用性;2、压缩的文件可以为任意文件,自由选择,并且解压其压缩后的文件显示其是否与原文件内容一致。

四.设计条件计算机、VC6.0编译环境五.参考资料李亦农、李梅《信息论基础教程》指导教师(签字):教研室主任(签字):批准日期:年月日哈夫曼编码(Huffman Coding)是一种编码方式,也是可变字长编码(VLC)的一种。

这种方法完全依据字符出现的概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫作哈夫曼编码。

对于M进制哈弗曼编码,为了提高编码效率,就要使长码的符号数量尽量少、概率尽量小,所以应使合并的信源符号位于缩减信源序列尽可能高的位置上,以减少再次合并的次数,充分利用短码。

本文将采用利用二进制哈夫曼编码来进行文件的压缩与解压。

在二进制哈夫曼编码中,得出码字、平均码长和编码效率,构造哈夫曼树,沿着根节点到叶节点从左到右依次为0、1,并且码字的频率由大到小排序。

在本文中采用Visual C++6.0进行编程,此程序中具有输入字符集大小和权值大小,构造哈夫曼树,并对原本的文件进行编码等功能。

关键词:哈弗曼编码;信源;哈夫曼树;Visual C++6.0;1课题描述 (1)2设计原理 (1)3 设计过程 (2)3.1软件介绍 (2)3.1.1 Visual C++ 6.0简介 (2)3.1.2主要部分 (2)3.2设计内容 (2)4编码程序分析及其结果 (3)总结 (7)参考文献 (7)1课题描述在这个信息量爆炸的时代,凡是能载荷一定信息量,且码字的平均长度最短,可分离的变长码的码字集合称为最佳变长码。

哈夫曼编码使用哈夫曼编码进行数据压缩与解压缩

哈夫曼编码使用哈夫曼编码进行数据压缩与解压缩

哈夫曼编码使用哈夫曼编码进行数据压缩与解压缩在信息技术发展的背景下,数据的传输和存储需求越来越大,如何高效地进行数据压缩成为了重要的课题之一。

哈夫曼编码是一种基于信息熵的编码技术,通过构建最优二叉树,实现了数据的高效压缩和解压缩。

在本文中,我们将探讨哈夫曼编码的原理和应用。

一、哈夫曼编码的原理哈夫曼编码是一种变长编码,它根据字符出现的频率构建一棵最优二叉树,频率较高的字符被赋予较短的编码,频率较低的字符则被赋予较长的编码。

这种编码方式具有无重复前缀码性质,即任意字符的编码都不是其他字符编码的前缀。

这样一来,在解码时就能够准确还原原始数据。

具体实现过程如下:1. 统计字符频率:对待编码的数据进行字符频率统计,得到每个字符出现的次数。

2. 构建哈夫曼树:根据字符频率构建一棵哈夫曼树。

树的每个节点表示一个字符,并且字符的频率决定节点的权重。

构建过程中,每次选择权重最小的两个节点合并形成新的节点,直到所有节点合并为一棵树。

3. 分配编码:从根节点出发,对哈夫曼树的每个子树进行遍历,左子树路径上追加0,右子树路径上追加1,直到到达叶节点。

这样,每个字符都能够找到对应的编码。

4. 进行数据压缩:根据字符的编码,将原始数据进行编码替换,形成压缩后的数据。

编码后的数据长度会变短,达到了数据压缩的目的。

二、哈夫曼编码的应用哈夫曼编码在数据压缩领域有着广泛的应用。

其中,最常见的应用场景是在无损压缩算法中。

通过哈夫曼编码,能够将原始数据进行高效压缩,并在解压缩时准确还原数据,但并不损失任何信息。

此外,哈夫曼编码还经常用于文件压缩、图像压缩和音频压缩等领域。

在文件压缩中,能够将大文件转换为更小的压缩文件,方便传输和存储。

在图像压缩中,通过对图像数据进行编码,能够减小图像文件的大小,提高传输效率。

在音频压缩中,通过压缩音频数据,减小文件大小,同时保持音频质量,实现高质量的音频传输。

三、哈夫曼编码的优缺点1. 优点:哈夫曼编码是一种高效的数据压缩技术,可以大幅度减小数据的存储和传输空间。

基于哈夫曼编码实现文本文件的压缩和解压缩实验报告模板

基于哈夫曼编码实现文本文件的压缩和解压缩实验报告模板

本科学生设计性实验报告软件工程技能实践Ⅰ项目组长陈启学号_*******专业软件工程班级_15软件7 班成员陈启杨林昌邓志远万胜实验项目名称_指导教师及职称__讲师__开课学期2015 至2016 学年第二学期一、实验设计方案1、实验任务与目的(简单介绍实验内容,说明实验任务和目的)1.1实验内容根据ascii码文件中各ascii字符出现的频率情况创建Haffman树,再将各字符对应的哈夫曼编码写入文件中,实现文件压缩。

对于给定的一组字符,可以根据其权值进行哈夫曼编码,并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。

能够分析文件,统计文件中出现的字符,再对文件进行编码,实现文件的压缩和解压缩,能够对于文件的压缩,比例进行统计,能够打印文件。

分析与设计哈夫曼树的存储结构,实现哈夫曼算法以及编码与译码基本功能,并对任意文本文件利用哈夫曼编码进行压缩得到压缩文件,然后进行解压缩得到解压文件。

1.2实验任务和目的1.2.1了解文件的概念。

1.2.2掌握线性链表的插入、删除等算法。

1.3.3掌握Huffman树的概念及构造方法。

1.4.4掌握二叉树的存储结构及遍历算法。

1.5.5利用Huffman树及Huffman编码,掌握实现文件压缩的一般原理。

2、实验思路(详细描述解决问题的整体思路、涉及的算法思想及数据结构等)2.1整体思路2.2涉及的算法思想及数据结构:2.2.1输入要压缩的文件首先运行的时候,用户主界面上有菜单提示该如何使用软件,根据菜单提示选择所要执行的项,依次进行,因为各个环节之间有先后顺序。

第一步为输入压缩软件的名称,由键盘输入文件路径和文件名称,读入字符数组中,打开该文件,按照提示进行压缩。

若打不开,则继续输入。

2.2.2读文件并计算字符频率文件将信息存放在字符数组中;计算每个字符出现的次数,申请一个结构体数组空间,用读取的字符减去字符结束符作为下标记录字符的频率。

2.2.3根据字符的频率,利用Huffman编码思想创建Huffman树将所记录的字符的频率作为权值来创建Huffman树,依次选择权值最小的两个字符作为左右孩子,其和作为父结点的权值,依次进行下去,直到所有的字符结点都成为叶子结点。

利用改进的哈夫曼编码实现文件的压缩与解压

利用改进的哈夫曼编码实现文件的压缩与解压
De c o mp r e s s i o n o f t h e Do c u me n t
L u Bi n g , L i u Xi n g h a i
( Z h e n g z h o u I n s t i t u t e o f L i g h t I n d u s t r y , C o mp u t e r a n d C o m mu n i c a t i o n E n g i n e e i r n g I n s t i t u t e , Z h e n g z h o u 4 5 0 0 0 2 , C h i n a )
p o s e d . Ac c o r d i n g t o t h e c l a s s i c Hu f ma n a l g o it r h m, u s i n g t h e h e a p s o r t t h o u g h t t o b u i l d t h e Hu f ma n t r e e a n d t h e Hu f - ma n c o d i n g ,t h i s me t h o d c a n r e d u c e t h e me mo r y r e a d a n d wr i t e t i me s , i mp r o v i n g t h e s y s t e m r e s p o n s e t i me . T h r o u g h t h e s e c o n d ma p p i n g , e a c h 8 e n c o d e d il f e b i n a y r i s c o n v e te r d i n t o a c o r r e s p o n d i n g c h a r a c t e r , i mp r o v e t h e c o mp r e s s i o n r a t i o o f i f l e s a n d e n s u r e t h e s e c u i r t y a n d c o n i f d e n t i a l i t y o f t h e r e s u l t i n g c o mp r e s s e d i f l e . F i n a l l y , t h r e e t e x t f i l e s c o mp r e s s i o n t e s t o n he t i mp r o v e d Hu f f ma n a l g o r i t h m, e x p e i r me n t s s h o w t h a t t h e i mp r o v e d a l g o r i t h m, t h e c o mp r e s s i o n r a t i o i s s l i g h t l y b e t —

java实现哈夫曼压缩与解压缩的方法

java实现哈夫曼压缩与解压缩的方法

java实现哈夫曼压缩与解压缩的⽅法⼀哈夫曼树以及⽂件压缩原理:1.哈夫曼树:给定N个权值作为N个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树。

哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近(频率越⾼的结点离根越进)。

以下数组为例,构建哈夫曼树int a[] = {0,1,2,3,4,5,6,7,8}我们可以发现以下规律1:9个数构成的哈夫曼树⼀共有17个结点,也就是可以n个数可以⽣产2*n-1个结点2:数字越⼤的数离根节点越近,越⼩的数离根节点越近。

2.如何利⽤haffman编码实现⽂件压缩:⽐如abc.txt⽂件中有以下字符:aaaabbbccde,1.进⾏字符统计aaaabbbccdea : 4次b : 3次c : 2次d : 1次e : 1次2.⽤统计结果构建哈夫曼树3.⽤哈夫曼树⽣成哈夫曼编码(从根结点开始,路径左边记为0,右边记为1):a的编码:1b的编码:01c的编码:000d的编码:0011e的编码:00104.哈夫曼编码代替字符,进⾏压缩。

源⽂件内容为:aaaabbbccde将源⽂件⽤对应的哈夫曼编码(haffman code)替换,则有:11110101 01000000 00110010 (总共3个字节)由此可见,源⽂件⼀共有11个字符,占11字节的内存,但是经过⽤haffman code替换之后,只占3个字节,这样就能达到压缩的⽬的⼆主要技术点:1.哈夫曼树算法(哈夫曼压缩的基本算法)2.哈希算法(字符统计时候会⽤到,也可以直接⽤HashMap统计)3.位运算(涉及到将指定位,置0或置1)4.java⽂件操作,以及缓冲操作。

5.存储模式(⼤端存储,⼩端存储,能看懂⽂件16进制的形式)7.设置压缩密码,解压输⼊密码解压(⼩编⾃⼰加的内容)三实现过程:以上述aaaabbbccde为例1.字符统计:public class FreqHuf {public static int BUFFER_SIZE = 1 << 18;int freq[] = new int[256];File file;int count;List<HuffmanFreq> list;FreqHuf(String pathname) throws Exception {list = new ArrayList<>();this.file = new File(pathname);if(!file.exists()){throw new Exception("⽂件不存在");}System.out.println("进⾏字符统计中");CensusChar();System.out.println("字符统计完毕");}public void CensusChar() throws IOException{int intchar;FileInputStream fis = new FileInputStream(file);System.out.println("统计中");//这种统计处理⽅案,速度极慢,不建议使⽤,以下采⽤缓存读数据。

基于哈夫曼编码实现文本文件的压缩和解压缩

基于哈夫曼编码实现文本文件的压缩和解压缩

#include <iostream>#include <sys/stat.h>#ifndef _UNISTD_H#define _UNISTD_H#include <io.h>#include <process.h>#endif /* _UNISTD_H */#include <stdio.h>#include<stdlib.h>#include <windows.h>#include <fstream>#include <vector>#include <algorithm>#include <cstring>using namespace std;typedef struct{int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef struct{char* data;int* num;int length;}TNode;typedef struct{char *data;char** HM;}Code;typedef char** HuffmanCode;bool IfEncode(){int choose;system("color 70");cout<<"\t 1.加密压缩 2.无密压缩"<<endl;cout<<"请输入选择:";cin>>choose;if(choose==1)return true;elsereturn false;}void Encode(vector<char>& v){char ch[30];v.push_back('@');system("color 70");cout<<"请输入压缩密码"<<endl;cin>>ch;for(int i=0;ch[i]!='\0';i++)v.push_back(ch[i]);v.push_back('\0');v.push_back('@');cout<<"开始压缩!"<<endl;}void ReadTxt(vector<char>& v){char ch;ifstream infile("test.txt",ios::in);if(!infile){cerr<<"open error"<<endl;exit(1);}if(IfEncode())Encode(v);while(infile.peek()!=EOF){infile.get(ch);v.push_back(ch);}infile.close();}void InitList(TNode& T){T.data=new char[256];T.num=new int[256];if(!T.data||!T.num)exit(1);T.length=0;}bool Find(TNode T,char ch){int i;for(i=0;i<T.length;i++)if(ch==T.data[i])return true;return false;}void TCount(vector<char> v1,TNode &T){int i,j=0;char ch;int m=v1.size();for(i=0;i<m;i++){ch=v1[i];if(!Find(T,ch)){T.data[j]=ch;T.num[j]=count(v1.begin(),v1.end(),ch);j++;T.length++;}}}void Select(HuffmanTree &HT,int m,int& s1,int& s2) {int k,j,n,min=32767;for(k=1;k<=m;k++){if(HT[k].parent==0)if(HT[k].weight<=min){j=k;min=HT[k].weight;}}s1=j;HT[j].parent=1;min=32767;for(k=1;k<=m;k++){if(HT[k].parent==0)if(HT[k].weight<=min){n=k;min=HT[k].weight;}}s2=n;}void CreateHuffmanTree (HuffmanTree &HT,TNode T,int length) {int m,i,s1,s2;if(length<=1)return;m=2*length-1;HT=new HTNode[m+1];for(i=1;i<=m;++i){HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;}for(i=1;i<=length;++i)HT[i].weight=T.num[i-1];for(i=length+1;i<=m;i++){Select(HT,i-1,s1,s2);HT[s1].parent=i;HT[s2].parent=i;HT[i].lchild=s1;HT[i].rchild=s2;HT[i].weight=HT[s1].weight+HT[s2].weight;}}void CreatHuffmanCode (HuffmanTree HT,HuffmanCode &HC,int n) {int i,f,c,start;HC=new char*[n+1];char* cd=new char[n];cd[n-1]='\0';for(i=1;i<=n;i++){start=n-1;c=i;f=HT[i].parent;while(f!=0){--start;if(HT[f].lchild==c)cd[start]='0';elsecd[start]='1';c=f;f=HT[f].parent;}HC[i]=new char[n-start];strcpy(HC[i],&cd[start]);}delete cd;}int getFileSizeSystemCall(char * strFileName){struct stat temp;stat(strFileName, &temp);return temp.st_size;}void Zip(HuffmanCode HC,vector<char> v,TNode T){int i=0,j=0,k=0;ofstream outfile("zip.txt",ios::out);if(!outfile){cerr<<"open error"<<endl;exit(1);}cout<<"输出哈夫曼编码"<<endl;for(i=0;i<v.size();i++){for(j=0;j<T.length;j++)if(T.data[j]==v[i])break;for(k=0;HC[j+1][k]!='\0';k++){ cout<<HC[j+1][k]<<" ";}for(k=0;HC[j+1][k]!='\0';k++)outfile<<HC[j+1][k];}cout<<endl;outfile.close();cout<<"正在压缩。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

利用哈夫曼编码实现压缩和解压缩1.问题描述利用哈夫曼编码.实现压缩和解压缩的数据元素具有如下形式:结点:weight:存储结点的权值parent:是结点双亲在向量中的下标lchild:结点的左儿子向量下标rchild:结点右儿子向量下标bits:位串.存放编码ch:字符start:编码在位串中的起始位置文件操作记录:b:记录字符在数组中的位置count:字符出现频率(权值)lch、rch、parent:定义哈夫曼树指针变量bits[256]:定义存储哈夫曼编码的数组2.功能需求对于给定的一组字符.可以根据其权值进行哈夫曼编码.并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。

能够分析文件.统计文件中出现的字符.再对文件进行编码.实现文件的压缩和解压缩.能够对于文件的压缩.比例进行统计.能够打印文件。

3.实现要点(1)构造哈弗曼树过程中.首先将初始森林的各根结点的双亲和左、右儿子指针置-1;叶子在向量T的前n个分量中.构成初始森林的n个结点;对森林中的树进行n次合并.并产生n-1个新结点.依次放入向量T的第i个分量中。

(2)编码过程中.从叶子T[i]出发.利用双亲的指针找到双亲T[p];再根据T[p]的孩子指针可以知道T[i]是T[p]的左儿子还是右儿子.若是左儿子.则生成代码0.否则生成代码1;(3)在文件压缩和解压过程中.主要参考网上资料.每个步骤都基本理解.并注上了详细解析。

4.函数定义功能:输入权重.构造一棵哈弗曼树void huffman(hftree T){if(n<1 || n > m)return;int i,j,p1,p2;float small1,small2;//初始化cout<<"请输入叶子权重(5个):"<<endl;for(i=0; i<n; i++){T[i].parent = -1;T[i].lchild = T[i].rchild = -1;}//输入叶子权值for(i=0; i<n; i++){cin>>T[i].weight;}for(i=n; i<m; i++){p1 = p2 = -1;small1 = small2 = MAX_FLOAT;for(j=0; j<=i-1; j++){if(T[j].parent != -1)continue;if(T[j].weight < small1){small2 = small1;small1 = T[j].weight;p2 = p1;p1 = j;}else if(T[j].weight < small2){small2 = T[j].weight;p2 = j;}}T[p1].parent = T[p2].parent = i;T[i].parent=-1;T[i].lchild=p1;T[i].rchild=p2;T[i].weight=small1 + small2;}cout<<"创建成功!"<<endl;}功能:对哈弗曼树进行编码void encode(codelist codes, hftree T){int i,c,p,start;cout<<"请输入需要编码的字符(5个):"<<endl;for(i=0; i<n; i++){cin>>codes[i].ch;start=n;c=i;p=T[i].parent;while(p!=-1){start--;if(T[p].lchild==c) codes[i].bits[start]='0';else codes[i].bits[start]='1';c=p;p=T[p].parent;}codes[i].start=start;}cout<<"输入成功!:"<<endl;cout<<"编码表:"<<endl;for(int x=0; x<n; x++){cout<<codes[x].ch<<": ";for(int q=codes[x].start;q<n;q++) cout<<codes[x].bits[q];cout<<endl;}}函数功能:对哈弗曼树进行解码void decode(codelist codes,hftree T) {int i,c,p,b;int endflag;endflag=-1;i=m-1;while(cin>>b,b!=endflag){if(b==0) i=T[i].lchild;else i=T[i].rchild;if(T[i].lchild==-1){cout<<codes[i].ch;i=m-1;}}if(i!=m-1)cout<<"编码有错!\n";}功能:对文件进行压缩.统计压缩率void compress(){char filename[255],outputfile[255],buf[512];unsigned char c;long i,j,m,n,f;long min1,pt1,flength,length1,length2;double div;FILE *ifp,*ofp;cout<<"\t请您输入需要压缩的文件:";cin>>filename;ifp=fopen(filename,"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n\n";return;}cout<<"\t请您输入压缩后的文件名:";cin>>outputfile;ofp=fopen(strcat(outputfile,".encode"),"wb");if(ofp==NULL){cout<<"\n\t压缩文件失败!\n\n";return;}flength=0;while(!feof(ifp)){fread(&c,1,1,ifp);header[c].count++; //字符重复出现频率+1flength++; //字符出现原文件长度+1}flength--;length1=flength; //原文件长度用作求压缩率的分母header[c].count--;for(i=0;i<512;i++){if(header[i].count!=0) header[i].b=(unsigned char)i;else header[i].b=0;header[i].parent=-1;header[i].lch=header[i].rch=-1; //对结点进行初始化}for(i=0;i<256;i++) //根据频率(权值)大小.对结点进行排序.选择较小的结点进树{for(j=i+1;j<256;j++){if(header[i].count<header[j].count){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}for(i=0;i<256;i++) if(header[i].count==0) break;n=i; //外部叶子结点数为n个时.内部结点数为n-1.整个哈夫曼树的需要的结点数为2*n-1.m=2*n-1;for(i=n;i<m;i++) //构建哈夫曼树{min1=999999999; //预设的最大权值.即结点出现的最大次数for(j=0;j<i;j++){if(header[j].parent!=-1) continue;//parent!=-1说明该结点已存在哈夫曼树中.跳出循环重新选择新结点*/if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count=header[pt1].count;header[pt1].parent=i; //依据parent域值(结点层数)确定树中结点之间的关系header[i].lch=pt1; //计算左分支权值大小min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1) continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count+=header[pt1].count;header[i].rch=pt1; //计算右分支权值大小header[pt1].parent=i;}for(i=0;i<n;i++) //哈夫曼无重复前缀编码{f=i;header[i].bits[0]=0; //根结点编码0while(header[f].parent!=-1){j=f;f=header[f].parent;if(header[f].lch==j) //置左分支编码0{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);//依次存储连接“0”“1”编码header[i].bits[0]='0';}else //置右分支编码1{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='1';}}}fseek(ifp,0,SEEK_SET); //从文件开始位置向前移动0字节.即定位到文件开始位置fwrite(&flength,sizeof(int),1,ofp);fseek(ofp,8,SEEK_SET);buf[0]=0; //定义缓冲区,它的二进制表示00000000f=0;pt1=8;while(!feof(ifp)){c=fgetc(ifp);f++;for(i=0;i<n;i++){if(c==header[i].b) break;}strcat(buf,header[i].bits);j=strlen(buf);c=0;while(j>=8) //对哈夫曼编码位操作进行压缩存储{for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++; //统计压缩后文件的长度strcpy(buf,buf+8); //一个字节一个字节拼接 j=strlen(buf);}if(f==flength) break;}if(j>0) //对哈夫曼编码位操作进行压缩存储{strcat(buf,"00000000");for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;}fseek(ofp,4,SEEK_SET);fwrite(&pt1,sizeof(long),1,ofp);fseek(ofp,pt1,SEEK_SET);fwrite(&n,sizeof(long),1,ofp);for(i=0;i<n;i++){fwrite(&(header[i].b),1,1,ofp);c=strlen(header[i].bits);fwrite(&c,1,1,ofp);j=strlen(header[i].bits);if(j%8!=0) //若存储的位数不是8的倍数.则补0 {for(f=j%8;f<8;f++)strcat(header[i].bits,"0");}while(header[i].bits[0]!=0){c=0;for(j=0;j<8;j++) //字符的有效存储不超过8位.则对有效位数左移实现两字符编码的连接{if(header[i].bits[j]=='1') c=(c<<1)|1; //|1不改变原位置上的“0”“1”值else c=c<<1;}strcpy(header[i].bits,header[i].bits+8); //把字符的编码按原先存储顺序连接fwrite(&c,1,1,ofp);}}length2=pt1--;div=((double)length1-(double)length2)/(double)length1; //计算文件的压缩率fclose(ifp);fclose(ofp);printf("\n\t压缩文件成功!\n");printf("\t压缩率为 %f%%\n\n",div*100);return;}函数功能:对文件解压缩void uncompress(){char filename[255],outputfile[255],buf[255],bx[255];unsigned char c;long i,j,m,n,f,p,l;long flength;FILE *ifp,*ofp;cout<<"\t请您输入需要解压缩的文件:";cin>>filename;ifp=fopen(strcat(filename,".encode"),"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n";return;}cout<<"\t请您输入解压缩后的文件名:";cin>>outputfile;ofp=fopen(outputfile,"wb");if(ofp==NULL){cout<<"\n\t解压缩文件失败!\n";return;}fread(&flength,sizeof(long),1,ifp); //读取原文件长度.对文件进行定位fread(&f,sizeof(long),1,ifp);fseek(ifp,f,SEEK_SET);fread(&n,sizeof(long),1,ifp);for(i=0;i<n;i++){fread(&header[i].b,1,1,ifp);fread(&c,1,1,ifp);p=(long)c; //读取原文件字符的权值header[i].count=p;header[i].bits[0]=0;if(p%8>0) m=p/8+1;else m=p/8;for(j=0;j<m;j++){fread(&c,1,1,ifp);f=c;itoa(f,buf,2); //将f转换为二进制表示的字符串f=strlen(buf);for(l=8;l>f;l--){strcat(header[i].bits,"0");}strcat(header[i].bits,buf);}header[i].bits[p]=0;}for(i=0;i<n;i++) //根据哈夫曼编码的长短.对结点进行排序{for(j=i+1;j<n;j++){if(strlen(header[i].bits)>strlen(header[j].bits)){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}p=strlen(header[n-1].bits);fseek(ifp,8,SEEK_SET);m=0;bx[0]=0;while(1) //通过哈夫曼编码的长短.依次解码.从原来的位存储还原到字节存储{while(strlen(bx)<(unsigned int)p){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--) //在单字节内对相应位置补0{strcat(bx,"0");}strcat(bx,buf);}for(i=0;i<n;i++){if(memcmp(header[i].bits,bx,header[i].count)==0) break;}strcpy(bx,bx+header[i].count);c=header[i].b;fwrite(&c,1,1,ofp);m++; //统计解压缩后文件的长度if(m==flength) break; //flength是原文件长度}fclose(ifp);fclose(ofp);cout<<"\n\t解压缩文件成功!\n";if(m==flength) //对解压缩后文件和原文件相同性比较进行判断(根据文件大小)cout<<"\t解压缩文件与原文件相同!\n\n";else cout<<"\t解压缩文件与原文件不同!\n\n";return;}5、总结和体会本次大作业与C++大作业有所不同.主要是利用构造数据结构解决问题.C++大作业主要体现类和文件读写功能。

相关文档
最新文档