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

合集下载

哈夫曼编解码压缩解压文件—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。

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

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

利用哈夫曼编码实现压缩和解压缩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++大作业主要体现类和文件读写功能。

哈夫曼编码在数据压缩中的应用

哈夫曼编码在数据压缩中的应用

哈夫曼编码在数据压缩中的应用哈夫曼编码是一种常用的数据压缩算法,广泛应用于通信、存储和传输等领域。

它以最小的存储空间来表示高频出现的字符,从而实现对数据的高效压缩。

本文将介绍哈夫曼编码的原理和应用,并探讨其在数据压缩中的重要性。

一、哈夫曼编码原理哈夫曼编码是一种无损压缩算法,它通过构建哈夫曼树来实现对数据的编码和解码。

其基本原理是将频率较高的字符用较短的编码表示,而频率较低的字符则用较长的编码表示,从而实现对数据的压缩。

具体实现时,哈夫曼编码通过以下几个步骤来完成:1. 统计字符出现的频率。

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

3. 根据哈夫曼树的结构,为每个字符分配相应的二进制编码。

4. 将原始数据转换为对应的哈夫曼编码。

5. 将编码后的数据存储或传输。

二、哈夫曼编码的应用1. 数据压缩哈夫曼编码在数据压缩中广泛应用。

通过使用最短的编码来表示高频字符,可以大大减小数据的存储空间和传输带宽。

尤其在图像、音频、视频等大数据文件的传输和存储中,哈夫曼编码可以有效地降低数据的体积。

2. 文件压缩与解压哈夫曼编码常被用于文件压缩和解压缩。

在压缩文件时,通过对文件中的字符进行编码,可以减小文件的大小,使其更容易存储和传输。

而在解压缩时,通过对哈夫曼编码进行解码,可以还原成原始的文件内容。

3. 数据传输与存储哈夫曼编码在数据传输和存储中也起到重要的作用。

在数据传输中,由于带宽的限制,通过对数据进行压缩可以提高传输效率。

而在数据存储中,通过对数据进行压缩可以节省存储空间,提高存储效率。

三、哈夫曼编码的优势相比其他压缩算法,哈夫曼编码有以下优势:1. 哈夫曼编码是一种无损压缩算法,不会丢失原始数据的任何信息。

2. 哈夫曼编码可以根据不同字符的频率分配不同长度的编码,使得高频字符的编码长度更短,从而提高压缩效率。

3. 哈夫曼编码可以根据具体应用场景进行定制,使其更好地适应不同数据的特点,提高压缩率。

四、总结哈夫曼编码在数据压缩中扮演着重要的角色,它通过构建哈夫曼树和分配不同长度的编码,实现对数据的高效压缩。

哈夫曼编码 压缩

哈夫曼编码 压缩

哈夫曼编码压缩标题:哈夫曼编码压缩:一个深度解析一、引言哈夫曼编码是一种用于数据压缩的算法,由戴维·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
实时处理
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

本文首先简要阐述哈夫曼算法的基本思想,然后介绍了使用哈夫曼算法进行文件压缩和解压缩的处理步骤,最后给出了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 类型的位缓冲中,可能多个编码才能填满一个位缓冲,每填满一次,将位缓冲区以单个字节的形式写入文件。

当文件遍历完成的时候,文件的压缩也就完成了。

二、文件解压:①读取词频:读取压缩文件,将每个字符的出现次数存入数组statistic②构造哈夫曼编码树:根据statistic数组构造哈夫曼编码树③继续读取压缩文件,对于每个字节,使用位运算得到每个位(BIT)。

对于每个BIT,根据BIT从根开始遍历哈夫曼树,如果BIT是0就走左分支,如果BIT 是1就走有分支,走到叶子节点的时候,输出对应的字符。

走到叶子节点后,重新从哈夫曼树根节点开始匹配每个位。

当整个压缩文件读取完毕时,文件解压缩也完成了。

上文介绍了基于哈夫曼算法的文件压缩和解压缩,下面给出基于上述思想的C 语言源代码,一共有5个文件,其中pq.h和pq.c是优先队列,compress.h和compress.c是压缩和解压缩的实现,main.c是测试文件。

pq.h和pq.c请参见《优先队列(priority_queue)的C语言实现》:/gropefor/blog/item/7d958eb68359cbe230add14e.html 另外三个文件内容如下:* File: compress.h* Purpose: To compress file using the Haffman algorithm* Author: puresky* Date: 2011/05/01*/#ifndef _FILE_COMPRESSION_H#define _FILE_COMPRESSION_H//Haffuman Tree Nodetypedef struct HaffumanTreeNode HTN;struct HaffumanTreeNode{char _ch; //characterint _count; //frequencystruct HaffumanTreeNode *_left; //left childstruct HaffumanTreeNode *_right;//rigth child};//FileCompress Struct#define BITS_PER_CHAR 8 //the number of bits in a char#define MAX_CHARS 256 //the max number of chars#define FILE_BUF_SIZE 8192 //the size of Buffer for FILE I/Otypedef struct FileCompressStruct FCS;struct FileCompressStruct{HTN *_haffuman; //A pointer to the root of hafumman tree unsigned int _charsCount; //To store the number of charsunsigned int _total; //Total bytes in a file.char *_dictionary[MAX_CHARS]; //to store the encoding of each characterint _statistic[MAX_CHARS]; //To store the number of each character };FCS *fcs_new();void fcs_compress(FCS *fcs, const char *inFileName, const char*outFileName);void fcs_decompress(FCS *fcs, const char *inFileName, const char*outFileName);void fcs_free(FCS *fcs);#endif* File: compress.c* Purpose: To compress file using the Haffman algorithm * Author: puresky* Date: 2011/05/01*/#include <stdio.h>#include <string.h>#include <stdlib.h>#include "compress.h"#include "pq.h"static const unsigned char mask[8] ={0x80, /* 10000000 */0x40, /* 01000000 */0x20, /* 00100000 */0x10, /* 00010000 */0x08, /* 00001000 */0x04, /* 00000100 */0x02, /* 00000010 */0x01 /* 00000001 */};//static functions of HTNstatic HTN *htn_new(char ch, int count){HTN *htn = (HTN *)malloc(sizeof(HTN));htn->_left = NULL;htn->_right = NULL;htn->_ch = ch;htn->_count = count;return htn;}static void htn_print_recursive(HTN *htn, int depth) {int i;if(htn){for(i = 0; i < depth; ++i)printf(" ");printf("%d:%d\n", htn->_ch, htn->_count); htn_print_recursive(htn->_left, depth + 1);htn_print_recursive(htn->_right, depth + 1);}}static void htn_print(HTN *htn){htn_print_recursive(htn, 0);}static void htn_free(HTN *htn){if(htn){htn_free(htn->_left);htn_free(htn->_right);free(htn);}}//static functions of FCSstatic void fcs_generate_statistic(FCS *fcs, const char *inFileName) {int ret, i;unsigned char buf[FILE_BUF_SIZE];FILE *pf = fopen(inFileName, "rb");if(!pf){fprintf(stderr, "can't open file:%s\n", inFileName);return;}while((ret = fread(buf, 1, FILE_BUF_SIZE, pf)) > 0){fcs->_total += ret;for(i = 0; i < ret; ++i){if(fcs->_statistic[buf[i]] == 0)fcs->_charsCount++;fcs->_statistic[buf[i]]++;}}fclose(pf);}static void fcs_create_haffuman_tree(FCS *fcs){int i, count;HTN *htn, *parent, *left, *right;KeyValue *kv, *kv1, *kv2;PriorityQueue *pq;pq = priority_queue_new(PRIORITY_MIN);for(i = 0; i < MAX_CHARS; ++i){if(fcs->_statistic[i]){htn = htn_new((char)i, fcs->_statistic[i]); kv = key_value_new(fcs->_statistic[i], htn); priority_queue_enqueue(pq, kv);}}//fprintf(stdout, "the number of haffuman leaf is %d\n", priority_queue_size(pq));while(!priority_queue_empty(pq)){//fprintf(stdout, "priority queue size:%d\n", priority_queue_size(pq));kv1 = priority_queue_dequeue(pq);kv2 = priority_queue_dequeue(pq);if(kv2 == NULL){fcs->_haffuman = kv1->_value;key_value_free(kv1, NULL);}else{left = (HTN *)kv1->_value;right = (HTN *)kv2->_value;count = left->_count + right->_count;key_value_free(kv1, NULL);key_value_free(kv2, NULL);parent = htn_new(0, count);parent->_left = left;parent->_right = right;kv = key_value_new(count, parent);priority_queue_enqueue(pq, kv);}}priority_queue_free(pq, NULL);//htn_print(fcs->_haffuman);}static void fcs_generate_dictionary_recursively(HTN *htn, char*dictionary[], char path[], int depth){char *code = NULL;if(htn){if(htn->_left == NULL && htn->_right == NULL){code = (char *)malloc(sizeof(char) * (depth + 1)); memset(code, 0, sizeof(char) * (depth + 1));memcpy(code, path, depth);dictionary[(unsigned char)htn->_ch] = code;}if(htn->_left){path[depth] = '0';fcs_generate_dictionary_recursively(htn->_left, dictionary, path, depth + 1);}if(htn->_right){path[depth] = '1';fcs_generate_dictionary_recursively(htn->_right, dictionary, path, depth + 1);}}}static void fcs_generate_dictionary(FCS *fcs){char path[32];fcs_generate_dictionary_recursively(fcs->_haffuman,fcs->_dictionary, path, 0);//fcs_print_dictionary(fcs);}static void fcs_print_dictionary(FCS *fcs){int i;for(i = 0; i < MAX_CHARS; ++i)if(fcs->_dictionary[i] != NULL)fprintf(stdout, "%d:%s\n", i, fcs->_dictionary[i]); }static void fcs_write_statistic(FCS *fcs, FILE *pf){int i;fprintf(pf, "%d\n", fcs->_charsCount);for(i = 0; i < MAX_CHARS; ++i)if(fcs->_statistic[i] != 0)fprintf(pf, "%d %d\n", i, fcs->_statistic[i]);}static void fcs_do_compress(FCS *fcs, const char *inFileName, const char* outFileName){int i, j, ret;char *dictEntry, len;unsigned int bytes;char bitBuf;int bitPos;unsigned char inBuf[FILE_BUF_SIZE];FILE *pfIn, *pfOut;pfIn = fopen(inFileName, "rb");if(!pfIn){fprintf(stderr, "can't open file:%s\n", inFileName);return;}pfOut = fopen(outFileName, "wb");if(!pfOut){fclose(pfIn);fprintf(stderr, "can't open file:%s\n", outFileName);return;}fcs_write_statistic(fcs, pfOut);bitBuf = 0x00;bitPos = 0;bytes = 0;while((ret = fread(inBuf, 1, FILE_BUF_SIZE, pfIn)) > 0){for(i = 0; i < ret; ++i){len = strlen(fcs->_dictionary[inBuf[i]]);dictEntry = fcs->_dictionary[inBuf[i]];//printf("%s\n", dictEntry);for(j = 0; j < len; ++j){if(dictEntry[j] == '1'){bitBuf |= mask[bitPos++];}else{bitPos++;}if(bitPos == BITS_PER_CHAR){fwrite(&bitBuf, 1, sizeof(bitBuf), pfOut);bitBuf = 0x00;bitPos = 0;bytes++;}}}}if(bitPos != 0){fwrite(&bitBuf, 1, sizeof(bitBuf), pfOut);bytes++;}fclose(pfIn);fclose(pfOut);printf("The compression ratio is:%f%%\n",(fcs->_total - bytes) * 100.0 / fcs->_total);}static void fcs_read_statistic(FCS *fcs, FILE *pf){int i, charsCount = 0;int ch;int num;fscanf(pf, "%d\n", &charsCount);fcs->_charsCount = charsCount;for(i = 0; i < charsCount; ++i){fscanf(pf, "%d %d\n", &ch, &num);fcs->_statistic[(unsigned int)ch] = num;fcs->_total += num;}}static void fcs_do_decompress(FCS *fcs, FILE *pfIn, const char*outFileName){int i, j, ret;unsigned char ch;HTN *htn;unsigned char buf[FILE_BUF_SIZE];unsigned char bitCode;int bitPos;FILE *pfOut;pfOut = fopen(outFileName, "wb");if(!pfOut){fprintf(stderr, "can't open file:%s\n", outFileName); return;}htn = fcs->_haffuman;bitCode = 0x00;bitPos = 0;while((ret = fread(buf, 1, FILE_BUF_SIZE, pfIn)) > 0){for(i = 0; i < ret; ++i){ch = buf[i];for(j = 0; j < BITS_PER_CHAR; ++j){if(ch & mask[j]){htn = htn->_right;}else{htn = htn->_left;}if(htn->_left == NULL && htn->_right == NULL) //leaf{if(fcs->_total > 0){fwrite(&htn->_ch, 1, sizeof(char), pfOut);fcs->_total--;}htn = fcs->_haffuman;}}}}fclose(pfOut);}//FCS functionsFCS *fcs_new(){FCS *fcs = (FCS *)malloc(sizeof(FCS));fcs->_charsCount = 0;fcs->_total = 0;memset(fcs->_statistic, 0, sizeof(fcs->_statistic));memset(fcs->_dictionary, 0, sizeof(fcs->_dictionary));fcs->_haffuman = NULL;return fcs;}void fcs_free(FCS *fcs){int i;if(fcs){if(fcs->_haffuman)htn_free(fcs->_haffuman);for(i = 0; i < MAX_CHARS; ++i)free(fcs->_dictionary[i]);free(fcs);}}void fcs_compress(FCS *fcs, const char *inFileName, const char*outFileName){fprintf(stdout, "To compress file: %s ...\n", inFileName);fcs_generate_statistic(fcs, inFileName);fcs_create_haffuman_tree(fcs);fcs_generate_dictionary(fcs);fcs_do_compress(fcs, inFileName, outFileName);fprintf(stdout, "The compressed data of file: %s stored at %s!\n", inFileName, outFileName);}void fcs_decompress(FCS *fcs, const char *inFileName, const char*outFileName){FILE *pfIn;fprintf(stdout, "To decompress file: %s ...\n", inFileName);pfIn= fopen(inFileName, "rb");if(!pfIn){fprintf(stderr, "can't open file: %s\n", inFileName);return ;}fcs_read_statistic(fcs, pfIn);fcs_create_haffuman_tree(fcs);fcs_generate_dictionary(fcs);fcs_do_decompress(fcs, pfIn, outFileName);fclose(pfIn);fprintf(stdout, "The decompressed data of file: %s stored at %s\n", inFileName, outFileName);}/** File: main.c* Purpose: testing File Compression* Author:puresky* Date: 2011/05/01*/#include <stdlib.h>#include "compress.h"const int DO_COMPRESS = 1;const int DO_DECOMPRESS = 1;const char *InFile = "data.txt"; //The file to compress.const char *CompressedFile = "data.hfm"; //Compressed data of the file. const char *OutFile = "data2.txt"; //The decompressed file of the data.int main(int argc, char **argv){//1. compress fileif(DO_COMPRESS){FCS *fcs1;fcs1 = fcs_new();fcs_compress(fcs1, InFile, CompressedFile);fcs_free(fcs1);}//2. decompress fileif(DO_DECOMPRESS){FCS *fcs2;fcs2 = fcs_new();fcs_decompress(fcs2, CompressedFile, OutFile);fcs_free(fcs2);}system("pause");return 0;}优先队列(priority_queue)和一般队列(queue)的函数接口一致,不同的是,优先队列每次出列的是整个队列中最小(或者最大)的元素。

相关文档
最新文档