霍夫曼编码对英文文本地压缩和解压缩.docx
- 文档编号:29879843
- 上传时间:2023-08-03
- 格式:DOCX
- 页数:13
- 大小:18.65KB
霍夫曼编码对英文文本地压缩和解压缩.docx
《霍夫曼编码对英文文本地压缩和解压缩.docx》由会员分享,可在线阅读,更多相关《霍夫曼编码对英文文本地压缩和解压缩.docx(13页珍藏版)》请在冰豆网上搜索。
霍夫曼编码对英文文本地压缩和解压缩
Huffman编码对英文文本的压缩和解压缩
中国地质大学计算机学院信息安全专业
信息论实验报告
#include
#include
#include
structhead{
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++;//字符重复出现频率+1
flength++;//字符出现原文件长度+1
}
flength--;
length1=flength;//原文件长度用作求压缩率的分母
header[c].count--;
for(i=0;i<512;i++){
if(header[i].count!
=0)
header[i].b=(unsignedchar)i;
/*将每个哈夫曼码值及其对应的ASCII码
存放在一维数组header[i]中,且编码表
中的下标和ASCII码满足顺序存放关系*/
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 tmp=header[i]; header[i]=header[j]; header[j]=tmp; } } } for(i=0;i<256;i++)//找到第一个空的header结点 if(header[i].count==0) break; n=i; m=2*n-1; for(i=n;i min1=999999999;//预设的最大权值,即结点出现的最大次数 for(j=0;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; header[i].lch=pt1; min1=999999999; for(j=0;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 f=i; header[i].bits[0]=0;//根结点编码0 while(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);/*用来将数据写入文件流中,参数flength 指向欲写入的数据地址,总共写入的字符数 以参数size*int来决定,返回实际写入的int数目*/ fseek(ofp,8,SEEK_SET); buf[0]=0;//定义缓冲区,它的二进制表示00000000 f=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;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;//添加最后一位为1 else c=c<<1;//添加最后一位为0 } fwrite(&c,1,1,ofp); pt1++; strcpy(buf,buf+8); j=strlen(buf); } if(f==flength) break; } if(j>0){//最后不满八位的buf处理 strcat(buf,"00000000");//buf后加八位0 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);//pt1统计了输出文件中的字符个数,包括了最后的'/0' fseek(ofp,pt1,SEEK_SET); fwrite(&n,sizeof(long),1,ofp);//n统计了权值不为0的header[]数量 for(i=0;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的倍数,则补0 for(f=j%8;f<8;f++) strcat(header[i].bits,"0"); } while(header[i].bits[0]! =0){/*字符的有效存储不超过8位,则对 有效位数左移实现两字符编码的连接, 可理解为前缀编码也被压缩过*/ c=0; for(j=0;j<8;j++){ if(header[i].bits[j]=='1') c=(c<<1)|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; } 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);//读入文件长度flength fread(&f,sizeof(long),1,ifp);//读入header数组的存储地址 fseek(ifp,f,SEEK_SET); fread(&n,sizeof(long),1,ifp);//读入header数组中元素的个数 for(i=0;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 fread(&c,1,1,ifp); f=c; itoa(f,buf,2);/*此处借鉴网络程序,包括itoa()函数 itoa()函数的作用为,把int型的f 化为二进制数,再变成char型存入buf*/ f=strlen(buf); for(l=8;l>f;l--){//在单字节内对相应位置补0 strcat(header[i].bits,"0"); } strcat(header[i].bits,buf); } header[i].bits[p]=0; } for(i=0;i for(j=i+1;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,1,ifp); f=c; itoa(f,buf,2); f=strlen(buf); for(l=8;l>f;l--){ strcat(bx,"0"); } strcat(bx,buf); } for(i=0;i if(memcmp(header[i].bits,bx,header[i].count)==0)/*此函数也为网络借鉴,memcmp函数此处的作用 是比较bx的相应位是否与header[i].bits相同, 若前header[i].count均相同,则返回0*/ break; } strcpy(bx,bx+header[i].count); c=header[i].b; fwrite(&c,1,1,ofp); m++;//m用来统计解压缩后文件的长度 if(m==flength)//检验是否与源文件长度匹配 break; } fclose(ifp); fclose(ofp); printf("\n\t解压缩文件成功! \n"); if(m==flength) printf("\t解压缩文件与原文件相同! \n\n"); else printf("\t解压缩文件与原文件不同! \n\n"); return; } intmain(){ intc; while (1){ printf("\tHuffman前缀编码压缩&解压缩BYPB09000816俞映洲\n"); printf("\t1.压缩2.解压缩0.退出\n"); do{//对用户输入进行容错处理 printf("\n\t*请选择相应功能编号(0-2): "); c=getch(); printf("%c\n",c); if(c! ='0'&&c! ='1'&&c! ='2'){ printf("\t请检查您的输入在0~2之间! 请再输入一遍! \n"); } }while(c! ='0'&&c! ='1'&&c! ='2'); if(c=='1')//调用压缩子函数 compress(); elseif(c=='2') uncompress();//调用解压缩子函数 else{ exit(0); } return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 霍夫曼 编码 英文 文本 压缩 和解