用哈夫曼树实现压缩解压.docx
《用哈夫曼树实现压缩解压.docx》由会员分享,可在线阅读,更多相关《用哈夫曼树实现压缩解压.docx(19页珍藏版)》请在冰豆网上搜索。
用哈夫曼树实现压缩解压
用哈夫曼树实现压缩解压
程序是用VC++6.0编译完成的,可以完成对任意文件的压缩解压(为方便寻找,压缩出的文件与待压缩文件在同一文件夹中),但压缩文件夹还不可以,另外该程序还能打印出压缩时所建立的哈夫曼树及哈夫曼编码。
源代码如下:
#include
#include
#include
#include
typedefstructnode
{
longw;
shortp,l,r;
}htnode,*htnp;
typedefstructhuffman_code
{
unsignedcharlen;
unsignedchar*codestr;
}hufcode;
typedefchar**huffmancode;
intinitial_files(char*source_filename,FILE**inp,char*obj_filename,FILE**outp);
char*create_filename(char*source_filename,char*obj_filename);
intcompress(char*source_filename,char*obj_filename);
longfrequency_data(FILE*in,longfre[]);
intsearch_set(htnpht,intn,int*s1,int*s2);
intcreate_hftree(longw[],intn,htnodeht[]);
intencode_hftree(htnphtp,intn,hufcodehc[]);
unsignedcharchars_to_bits(constunsignedcharchars[8]);
intwrite_compress_file(FILE*in,FILE*out,htnpht,hufcodehc[],char*source_filename,longsource_filesize);
intdecompress(char*source_filename,char*obj_filename);
voidget_mini_huffmantree(FILE*in,shortmini_ht[][2]);
intwrite_decompress_file(FILE*in,FILE*out,shortmini_ht[][2],longbits_pos,longobj_filesize);
intd_initial_files(char*source_filename,FILE**inp,char*obj_filename,FILE**outp);
main()
{
ints;
charfilename[10];
system("color3F");
printf("***************************************\n");
printf("*菜单:
*\n");
printf("*1.——————压缩——————*\n");
printf("*2.—————-解压缩—————-*\n");
printf("*0.——————退出——————*\n");
printf("***************************************\n");
scanf("%d",&s);
while(s!
=0)
{
getchar();
switch(s)
{
case1:
puts("请输入待压缩文件路径:
");
gets(filename);
compress(filename,NULL);
break;
case2:
puts("请输入待解压文件路径:
");
gets(filename);
decompress(filename,NULL);
break;
default:
printf("指令错误!
请重新输入指令:
\n");
}
puts("");
printf("***************************************\n");
printf("*菜单:
*\n");
printf("*1.——————压缩——————*\n");
printf("*2.—————-解压缩—————-*\n");
printf("*0.——————退出——————*\n");
printf("***************************************\n");
scanf("%d",&s);
}
}
intinitial_files(char*source_filename,FILE**inp,char*obj_filename,FILE**outp)
{
if(fopen(source_filename,"rb")==NULL)
{
return-1;
}
if(obj_filename==NULL)
{
if((obj_filename=(char*)malloc(256*sizeof(char)))==NULL)
{
return-1;
}
create_filename(source_filename,obj_filename);
}
if(strcmp(source_filename,obj_filename)==0)
{
return-1;
}
printf("待压缩文件:
%s,压缩文件:
%s\n",source_filename,obj_filename);
if((*outp=fopen(obj_filename,"wb"))==NULL)
{
return-1;
}
if((*inp=fopen(source_filename,"rb"))==NULL)
{
return-1;
}
free(obj_filename);
return0;
}
char*create_filename(char*source_filename,char*obj_filename)
{
char*temp;
if((temp=strrchr(source_filename,'.'))==NULL)
{
strcpy(obj_filename,source_filename);
strcat(obj_filename,".zip");
}
else
{
strncpy(obj_filename,source_filename,temp-source_filename);
obj_filename[temp-source_filename]='\0';
strcat(obj_filename,".zip");
}
returnobj_filename;
}
intcompress(char*source_filename,char*obj_filename)
{
FILE*in,*out;
charch;
interror_code,i,j;
floatcompress_rate;
hufcodehc[256];
htnodeht[256*2-1];
longfrequency[256],source_filesize,obj_filesize=0;
error_code=initial_files(source_filename,&in,obj_filename,&out);
if(error_code!
=0)
{
puts("文件打开失败!
请重新输入文件路径:
");
returnerror_code;
}
source_filesize=frequency_data(in,frequency);
printf("文件大小%ld字节\n",source_filesize);
error_code=create_hftree(frequency,256,ht);
if(error_code!
=0)
{
puts("建立哈夫曼树失败!
");
returnerror_code;
}
error_code=encode_hftree(ht,256,hc);
if(error_code!
=0)
{
puts("建立哈夫曼编码失败!
");
returnerror_code;
}
for(i=0;i<256;i++)
obj_filesize+=frequency[i]*hc[i].len;
obj_filesize=obj_filesize%8==0?
obj_filesize/8:
obj_filesize/8+1;
for(i=0;i<256-1;i++)
obj_filesize+=2*sizeof(short);
obj_filesize+=strlen(source_filename)+1;
obj_filesize+=sizeof(long);
obj_filesize+=sizeof(unsignedint);
compress_rate=(float)obj_filesize/source_filesize;
printf("压缩文件大小:
%ld字节,压缩比例:
%.2lf%%\n",obj_filesize,compress_rate*100);
error_code=write_compress_file(in,out,ht,hc,source_filename,source_filesize);
if(error_code!
=0)
{
puts("写入文件失败!
");
returnerror_code;
}
puts("压缩完成!
");
puts("");
puts("是否打印该文件中字符对应的huffman树及编码?
");
puts("PleaseinputYORN");
do{
scanf("%s",&ch);
switch(ch)
{
case'Y':
puts("以下是哈夫曼树:
");
for(i=256;i<256*2-2;i++)
{
if(ht[i].w>0)
printf("%-10d%-10d%-10d%-10d%-10d\n",i,ht[i].w,ht[i].p,ht[i].l,ht[i].r);
}
puts("以下是哈夫曼编码:
");
for(i=0;i<256;i++)
{
if(frequency[i]==0)
i++;
else
{
printf("%d\t",frequency[i]);
for(j=0;jprintf("%d",hc[i].codestr[j]);
printf("\n");
}
}
break;
case'N':
break;
default:
printf("指令错误!
请重新输入指令:
\n");
}
}while(ch!
='Y'&&ch!
='N');
fclose(in);
fclose(out);
for(i=0;i<256;i++)
{
free(hc[i].codestr);
}
return0;
}
longfrequency_data(FILE*in,longfrequency[])
{
inti,read_len;
unsignedcharbuf[256];
longfilesize;
for(i=0;i<256;i++)
{
frequency[i]=0;
}
fseek(in,0L,SEEK_SET);
read_len=256;
while(read_len==256)
{
read_len=fread(buf,1,256,in);
for(i=0;i{
frequency[*(buf+i)]++;
}
}
for(i=0,filesize=0;i<256;i++)
{
filesize+=frequency[i];
}
returnfilesize;
}
intsearch_set(htnpht,intn,int*s1,int*s2)
{
inti,x;
longminValue=1000000,min=0;
for(x=0;x{
if(ht[x].p==-1)break;
}
for(i=0;i{
if(ht[i].p==-1&&ht[i].w{
minValue=ht[i].w;
min=i;
}
}
*s1=min;
minValue=1000000,min=0;
for(i=0;i{
if(ht[i].p==-1&&ht[i].w=*s1)
{
minValue=ht[i].w;
min=i;
}
}
*s2=min;
return1;
}
intcreate_hftree(longw[],intn,htnodeht[])
{
intm,i,s1,s2;
if(n<1)return-1;
m=2*n-1;
if(ht==NULL)return-1;
for(i=0;i{
ht[i].w=w[i];
ht[i].p=ht[i].l=ht[i].r=-1;
}
for(;i{
ht[i].w=ht[i].p=ht[i].l=ht[i].r=-1;
}
for(i=n;i{
search_set(ht,i,&s1,&s2);
ht[s1].p=ht[s2].p=i;
ht[i].l=s1;
ht[i].r=s2;
ht[i].w=ht[s1].w+ht[s2].w;
}
return0;
}
intencode_hftree(htnphtp,intn,hufcodehc[])
{
inti,j,p,codelen;
unsignedchar*code=(unsignedchar*)malloc(n*sizeof(unsignedchar));
if(code==NULL)return-1;
for(i=0;i{
for(p=i,codelen=0;p!
=2*n-2;p=htp[p].p,codelen++)
{
code[codelen]=(htp[htp[p].p].l==p?
0:
1);
}
if((hc[i].codestr=(unsignedchar*)malloc((codelen)*sizeof(unsignedchar)))==NULL)
{
return-1;
}
hc[i].len=codelen;
for(j=0;j{
hc[i].codestr[j]=code[codelen-j-1];
}
}
free(code);
return0;
}
unsignedcharchars_to_bits(constunsignedcharchars[8])
{
inti;
unsignedcharbits=0;
bits|=chars[0];
for(i=1;i<8;++i)
{
bits<<=1;
bits|=chars[i];
}
returnbits;
}
intwrite_compress_file(FILE*in,FILE*out,htnpht,hufcodehc[],char*source_filename,longsource_filesize)
{
unsignedinti,read_counter,write_counter,zip_head=0xFFFFFFFF;
unsignedcharwrite_char_counter,code_char_counter,copy_char_counter,
read_buf[256],write_buf[256],write_chars[8],filename_size=strlen(source_filename);
hufcode*cur_hufcode;
fseek(in,0L,SEEK_SET);
fseek(out,0L,SEEK_SET);
fwrite(&zip_head,sizeof(unsignedint),1,out);
fwrite(&filename_size,sizeof(unsignedchar),1,out);
fwrite(source_filename,sizeof(char),filename_size,out);
fwrite(&source_filesize,sizeof(long),1,out);
for(i=256;i<256*2-1;i++)
{
fwrite(&(ht[i].l),sizeof(ht[i].l),1,out);
fwrite(&(ht[i].r),sizeof(ht[i].r),1,out);
}
write_counter=write_char_counter=0;
read_counter=256;
while(read_counter==256)
{
read_counter=fread(read_buf,1,256,in);
for(i=0;i{
cur_hufcode=&hc[read_buf[i]];
code_char_counter=0;
while(code_char_counter!
=cur_hufcode->len)
{
copy_char_counter=(8-write_char_counter>cur_hufcode->len-code_char_counter?
cur_hufcode->len-code_char_counter:
8-write_char_counter);
memcpy(write_chars+write_char_counter,cur_hufcode->codestr+code_char_counter,copy_char_counter);
write_char_counter+=copy_char_counter;
code_char_counter+=copy_char_counter;
if(write_char_counter==8)
{
write_char_counter=0;
write_buf[write_counter++]=chars_to_bits(write_chars);
if(write_counter==256)
{
fwrite(write_buf,1,256,out);
write_counter=0;
}
}
}
}
}
fwrite(write_buf,1,write_counter,out);
if(write_char_counter!
=0)
{
write_char_counter=chars_to_bits(write_chars);
fwrite(&write_char_counter,1,1,out);
}
return0;
}
voidget_mini_huffmantree(FILE*in,shortmini_ht[][2])
{
inti;
for(i=0;i<256;i++)
{
mini_ht[i][0]=mini_ht[i][1]=-1;
}
fread(mini_ht[i],sizeof(short),2*(256-1),in);
}
intwrite_decompress_file(FILE*in,FILE*out,shortmini_ht[][2],longbits_pos,longobj_filesize)
{
longcur_size;
unsignedcharread_buf[256],write_buf[256],convert_bit;
unsignedintread_counter,write_counter,cur_pos;
fseek(in,bits_pos,SEEK_SET);
fseek(out,0L,SEEK_SET);
read_counter=256-1;
cur_size=write_counter=0;
cur_pos=256*2-2;
while(cur_size!
=obj_filesize)
{
if(++read_counter==256)
{
fread(read_buf,1,256,in);
read_counter=0;
}
for(convert_bit=128;convert_bit!
=0;convert_bit>>=1)
{
cur_pos=((read_buf[read_counter]&convert_bit)==0?
mini_ht[cur_pos][0]:
mini_ht[cur_pos