您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 霍夫曼编码对英文文本的压缩和解压缩
Huffman编码对英文文本的压缩和解压缩中国地质大学计算机学院信息安全专业信息论实验报告#includestdio.h#includestring.h#includeconio.hstructhead{unsignedcharb;//记录字符在数组中的位置longcount;//字符出现频率(权值)longparent,lch,rch;//定义哈夫曼树指针变量charbits[256];//定义存储哈夫曼编码的数组}header[512],tmp;voidcompress(){charfilename[255],outputfile[255],buf[512];unsignedcharc;longn,m,i,j,f;//作计数或暂时存储数据用longmin1,pt1,flength=0,length1,length2;//记录最小结点、文件长度doublediv;//计算压缩比用FILE*ifp,*ofp;//分别为输入、输出文件指针printf(\t请您输入需要压缩的文件(需要路径):);gets(filename);ifp=fopen(filename,rb);if(ifp==NULL){printf(\n\t文件打开失败!\n);system(pause);return;}printf(\t请您输入压缩后的文件名(如无路径则默认为桌面文件):);gets(outputfile);ofp=fopen(outputfile,wb);if(ofp==NULL){printf(\n\t压缩文件失败!\n);system(pause);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;i512;i++){if(header[i].count!=0)header[i].b=(unsignedchar)i;/*将每个哈夫曼码值及其对应的ASCII码存放在一维数组header[i]中,且编码表中的下标和ASCII码满足顺序存放关系*/elseheader[i].b=0;header[i].parent=-1;header[i].lch=header[i].rch=-1;//对结点进行初始化}for(i=0;i256;i++){//按出现权值从大到小排序for(j=i+1;j256;j++){if(header[i].countheader[j].count){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}for(i=0;i256;i++)//找到第一个空的header结点if(header[i].count==0)break;n=i;m=2*n-1;for(i=n;im;i++){min1=999999999;//预设的最大权值,即结点出现的最大次数for(j=0;ji;j++){if(header[j].parent!=-1)continue;/*parent!=-1说明该结点已存在哈夫曼树中,跳出循环重新选择新结点*/if(min1header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count=header[pt1].count;header[pt1].parent=i;header[i].lch=pt1;min1=999999999;for(j=0;ji;j++){if(header[j].parent!=-1)continue;if(min1header[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;in;i++){f=i;header[i].bits[0]=0;//根结点编码0while(header[f].parent!=-1){j=f;f=header[f].parent;if(header[f].lch==j){//置左分支编码0j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);//依次存储连接01编码,此处语句为网络借鉴header[i].bits[0]='0';}else{//置右分支编码1j=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);/*用来将数据写入文件流中,参数flength指向欲写入的数据地址,总共写入的字符数以参数size*int来决定,返回实际写入的int数目*/fseek(ofp,8,SEEK_SET);buf[0]=0;//定义缓冲区,它的二进制表示00000000f=0;pt1=8;/*假设原文件第一个字符是A,8位2进制为01000001,编码后为0110识别编码第一个'0',那么将其左移一位,看起来没什么变化。下一个是'1',应该|1,结果00000001同理4位都做完,应该是00000110,由于字节中的8位并没有全部用完,继续读下一个字符,根据编码表继续拼完剩下4位,如果字符的编码不足4位,还要继续读一个字符,如果字符编码超过4位,那么把剩下的位信息拼接到一个新的字节里*/while(!feof(ifp)){c=fgetc(ifp);f++;for(i=0;in;i++){//找到对应的header[i]if(c==header[i].b)break;}strcat(buf,header[i].bits);j=strlen(buf);c=0;while(j=8){for(i=0;i8;i++){if(buf[i]=='1')c=(c1)|1;//添加最后一位为1elsec=c1;//添加最后一位为0}fwrite(&c,1,1,ofp);pt1++;strcpy(buf,buf+8);j=strlen(buf);}if(f==flength)break;}if(j0){//最后不满八位的buf处理strcat(buf,00000000);//buf后加八位0for(i=0;i8;i++){//逐位输入八位前的二进制符if(buf[i]=='1')c=(c1)|1;elsec=c1;}fwrite(&c,1,1,ofp);pt1++;}fseek(ofp,4,SEEK_SET);//指针回到输出文件头部后面四位fwrite(&pt1,sizeof(long),1,ofp);//pt1统计了输出文件中的字符个数,包括了最后的'/0'fseek(ofp,pt1,SEEK_SET);fwrite(&n,sizeof(long),1,ofp);//n统计了权值不为0的header[]数量for(i=0;in;i++){fwrite(&(header[i].b),1,1,ofp);//依次写入每个叶子结点的b、长度和内容c=strlen(header[i].bits);fwrite(&c,1,1,ofp);j=strlen(header[i].bits);if(j%8!=0){//若存储的位数不是8的倍数,则补0for(f=j%8;f8;f++)strcat(header[i].bits,0);}while(header[i].bits[0]!=0){/*字符的有效存储不超过8位,则对有效位数左移实现两字符编码的连接,可理解为前缀编码也被压缩过*/c=0;for(j=0;j8;j++){if(header[i].bits[j]=='1')c=(c1)|1;elsec=c1;}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;}voiduncompress(){charfilename[255],outputfile[255],buf[255],bx[255];unsignedcharc;longi,j,m,n,f,p,l;longflength;FILE*ifp,*ofp;printf(\t请您输入需要解压缩的文件(如无路径则默认为桌面文件):);gets(filename);ifp=fopen(filename,rb);if(ifp==NULL){printf(\n\t文件打开失败!\n);system(pause);return;}printf(\t请您输入解压缩后的文件名:);gets(outputfile);ofp=fopen(outputfile,wb);if(ofp==NULL){printf(\n\t解压缩文件失败!\n);system(pause);return;}fread(&flength,sizeof(long),1,ifp);//读入文件长度flengthfread(&f,sizeof(long),1,ifp);//读入header数组的存储地址fseek(ifp,f,SEEK_SET);fread(&n,sizeof(long),1,ifp);//读入header数组中元素的个数for(i=0;in;i++){//读入header数组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%80)m=p/8+1;elsem=p/8;for(j=0;jm;j++){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);/*此处借鉴网络程序,包括itoa()函数itoa()函数的作用为,把int型的f化为二进制数,再变成char型存入buf*/f=strlen(buf);for(l=8;lf;l--){//在单字节内对相应位置补0strcat(header[i].bits,0);}strcat(header[i].bits,buf);}header[i].bits[p]=0;}for(i=0;in;i++){//按Huffman编码从小到大排序for(j=i+1;jn;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)(unsignedint)p){fread(&c,1,
本文标题:霍夫曼编码对英文文本的压缩和解压缩
链接地址:https://www.777doc.com/doc-2723239 .html