这也是我们做的作业,哈夫曼编码可用于压缩解压缩,平时我们用的rar也差不多是用这个原理来压缩的。代码主体也是从网上拷的,而且这个程序说实话,并没有付入很多心血,注释也很少,给大家看看吧:
#include
#include
using namespace std;
typedef struct huffNode
{
int parent,lchild,rchild;
unsigned long count;
unsigned char c;
char bits[256];
}HuffNode;
HuffNode HTree[512],temp;
void compress();
void uncompress();
void main()
{
char a;
while(1)
{
cout<<" 压缩、解压缩工具 /n/n";
cout<<"功能:/n";
cout<<" 1.压缩/n";
cout<<" 2.解压缩/n";
cout<<" 3.退出/n/n";
cout<<"注意:使用本软件压缩后压缩文件后缀名为ty/n";
cout<<" 压缩和解压时不需输入压缩文件的后缀名/n/n";
cout<<"请选择操作:";
cin>>a;
while(a!='1' && a!='2' && a!='3')
{
cout<<"无效的输入!/n";
cout<<"请选择操作:";
cin>>a;
}
if(a=='1')
compress();
else if(a=='2')
uncompress();
else
exit(0);
system("cls");
}
}
/************压缩************/
void compress()
{
FILE *infile,*outfile;
char infilename[255],outfilename[255];
cout<<"/n请输入要压缩的文件名:";
cin>>infilename;
fopen_s(&infile,infilename,"rb");
while(infile==NULL)
{
char a;
cout<<"文件"<
cin>>a;
while(a!='1'&& a!='2')
{
cout<<"/n无效的输入!/n";
cout<<"重新输入文件名(1)或返回主菜单(2)?";
cin>>a;
}
if(a=='2')
break;
else
{
cout<<"/n请输入要压缩的文件名:";
cin>>infilename;
fopen_s(&infile,infilename,"rb");
}
}
/*cout<<"/n输入压缩后的文件名:";
cin>>outfilename;*/
strcpy_s(outfilename,sizeof(outfilename),infilename);
strcat_s(outfilename,sizeof(outfilename),".ty");
fopen_s(&outfile,outfilename,"wb");
if(outfile==NULL)
{
cout<<"/n压缩文件失败!无法创建压缩后的文件...";
cout<<"/n按任意键回到主菜单...";
_getch();
return;
}
cout<<"压缩文件中...";
//定义各变量
int i,j,k;
int used; //用到的字符数
unsigned long total=0; //文件长度
//每个叶子节点赋值
for(i=0;i<512;i++)
{
HTree[i].count=0;
HTree[i].c=(unsigned char)i;
HTree[i].lchild=-1;
HTree[i].parent=-1;
HTree[i].rchild=-1;
}
//统计各个字符出现次数
unsigned char c;
while(!feof(infile))
{
fread(&c,1,1,infile);
HTree[c].count++;
total++;
}
total--;
HTree[c].count--;
//count为0的不要,按count从大到小排列
for(i=0;i<255;i++)
{
for(j=i+1;j<256;j++)
{
if(HTree[i].count
temp=HTree[i];
HTree[i]=HTree[j];
HTree[j]=temp;
}
}
}
//有用字符数
for(i=0;i<512;i++)
if(HTree[i].count==0)
break;
used=i-1;
//构建哈夫曼树
unsigned long min;
int m=2*i-1;
int pt;
for(i;i
min=3435973836;
for(j=0;j {
if(HTree[j].parent!=-1)
continue;
if(min>HTree[j].count)
{
pt=j;
min=HTree[j].count;
}
}
HTree[i].count=min;
HTree[pt].parent=i;
HTree[i].lchild=pt;
min=3435973836;
for(j=0;j {
if(HTree[j].parent!=-1)
continue;
if(min>HTree[j].count)
{
pt=j;
min=HTree[j].count;
}
}
HTree[i].count+=min;
HTree[pt].parent=i;
HTree[i].rchild=pt;
}
//为每个有权值的字符编码
for(i=0;i<=used;i++)
{
k=i;
HTree[i].bits[0]=0;
while(HTree[k].parent!=-1)
{
j=k;
k=HTree[k].parent;
if(HTree[k].lchild==j)
{
j=strlen(HTree[i].bits);
memmove(HTree[i].bits+1,HTree[i].bits,j+1);
HTree[i].bits[0]='0';
}
else
{
j=strlen(HTree[i].bits);
memmove(HTree[i].bits+1,HTree[i].bits,j+1);
HTree[i].bits[0]='1';
}
}
}
//写头文件
char buf[512];
fseek(infile,0,0);
fwrite(&total,sizeof(unsigned long),1,outfile); //原文件总长度
fwrite(&used,sizeof(int),1,outfile);
int maxCSize=0; //最长的字符编码
for(i=0;i<=used;i++)
{
if(maxCSize
}
fwrite(&maxCSize,sizeof(int),1,outfile);
for(i=0;i<=used;i++)
{
fwrite(&HTree[i].c,sizeof(unsigned char),1,outfile);
fwrite(&HTree[i].bits,maxCSize,1,outfile);
}
//开始压缩主文件
j=0; //最大为total
buf[0]=0;
pt=12+5*used;
while(!feof(infile))
{
c=fgetc(infile);
j++;
for(i=0;i<=used;i++)
{
if(HTree[i].c==c)
break;
}
strcat(buf,HTree[i].bits);
k=strlen(buf);
c=0;
while(k>=8)
{
for(i=0;i<8;i++)
{
if(buf[i]=='1')
c=(c<<1)|1;
else
c=c<<1;
}
fwrite(&c,1,1,outfile);
pt++;
strcpy(buf,buf+8);
k=strlen(buf);
}
if(j==total)
break;
}
if(k>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,outfile);
pt++;
}
fclose(infile);
fclose(outfile);
cout<<"压缩成功!/n";
float s;
s=(float)pt/(float)total;
cout<<"压缩率为:"< _getch();
return;
}
/************解压缩**************/
void uncompress()
{
FILE *infile,*outfile;
char infilename[255],outfilename[255];
cout<<"请输入要解压的文件名:";
cin>>infilename;
strcpy_s(outfilename,sizeof(outfilename),infilename);
strcat_s(infilename,sizeof(infilename),".ty");
fopen_s(&infile,infilename,"rb");
while(infile==NULL)
{
char a;
cout<<"文件"<
cin>>a;
while(a!='1'&& a!='2')
{
cout<<"/n无效的输入!/n";
cout<<"重新输入文件名(1)或返回主菜单(2)?";
cin>>a;
}
if(a=='2')
break;
else
{
cout<<"/n请输入要解压的文件名:";
cin>>infilename;
strcat_s(infilename,sizeof(infilename),".ty");
fopen_s(&infile,infilename,"rb");
}
}
//cout<<"/n输入解压后的文件名:";
//cin>>outfilename;
fopen_s(&outfile,outfilename,"wb");
if(outfile==NULL)
{
cout<<"/n解压文件失败!无法创建解压后的文件...";
cout<<"/n按任意键回到主菜单...";
_getch();
return;
}
cout<<"解压文件中...";
//开始解压
int i,j,k,l;
int used; //用到的字符数
unsigned long total=0; //文件长度
char buf[256],bx[256];
unsigned char c;
int maxCSize;
fread(&total,sizeof(unsigned long),1,infile);
fread(&used,sizeof(int),1,infile);
fread(&maxCSize,sizeof(int),1,infile);
for(i=0;i<=used;i++)
{
fread(&HTree[i].c,sizeof(unsigned char),1,infile);
fread(&HTree[i].bits,maxCSize,1,infile);
}
//开始解压
j=0;
bx[0]=0;
while(1)
{
while(strlen(bx)
fread(&c,1,1,infile);
k=c;
itoa(k,buf,2);
k=strlen(buf);
for(l=8;l>k;l--) //在单字节内对相应位置补0
{
strcat(bx,"0");
}
strcat(bx,buf);
}
for(i=0;i<=used;i++)
{
if(memcmp(HTree[i].bits,bx,strlen(HTree[i].bits))==0) break;
}
strcpy(bx,bx+strlen(HTree[i].bits));
c=HTree[i].c;
fwrite(&c,1,1,outfile);
j++; //统计解压缩后文件的长度
if(j==total) break;
}
fclose(infile);
fclose(outfile);
cout<<"解压成功!";
cout<<"/n任意键返回主界面";
_getch();
return;
}
VS2005上编译成功的,大家有什么意见也欢迎回复。