霍夫曼编码对英文文本地压缩和解压缩.docx

上传人:b****5 文档编号:29879843 上传时间:2023-08-03 格式:DOCX 页数:13 大小:18.65KB
下载 相关 举报
霍夫曼编码对英文文本地压缩和解压缩.docx_第1页
第1页 / 共13页
霍夫曼编码对英文文本地压缩和解压缩.docx_第2页
第2页 / 共13页
霍夫曼编码对英文文本地压缩和解压缩.docx_第3页
第3页 / 共13页
霍夫曼编码对英文文本地压缩和解压缩.docx_第4页
第4页 / 共13页
霍夫曼编码对英文文本地压缩和解压缩.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

霍夫曼编码对英文文本地压缩和解压缩.docx

《霍夫曼编码对英文文本地压缩和解压缩.docx》由会员分享,可在线阅读,更多相关《霍夫曼编码对英文文本地压缩和解压缩.docx(13页珍藏版)》请在冰豆网上搜索。

霍夫曼编码对英文文本地压缩和解压缩.docx

霍夫曼编码对英文文本地压缩和解压缩

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;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 调查报告

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1