使用哈夫曼编码对文本文件进行压缩。
#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<conio.h>
#include<windows.h>
#include<algorithm>
#include<iostream>
using namespace std;
typedef unsigned char uc;
typedef unsigned long long ull;
string s2;
vector<int>G[512];//用vector存储哈夫曼树
typedef vector<int>::iterator ITER;
string anss[256];
typedef pair<int,int> data;//堆中存储的数据类型为pair<int,int>
#define N 1000000
uc sp[N+5];
int lenp;
char s[N+5],table[256];
int n,m;
int cnts[256];//记录各字符出现频率
int ReadIn(FILE* fp);//读入文本文件,返回其总长度
void Freq_stats();//统计各字符出现频率
void dfs(int U,string s);//深度优先遍历哈夫曼树,生成每个字符的哈夫曼编码
void HuffmanCoding();//用堆实现哈夫曼编码主过程
int main(){
int op;
char ch;
while(1){
system("cls");
printf("请输入对应数字选择您想要的功能:\n");
printf("1.压缩当前目录下的test.txt文件到test.comp,并且输出各字符出现频率以及编码表。\n");
printf("2.解压当前目录下的test.comp文件,并且输出原文本到test2.txt。\n");
printf("3.退出程序。\n");
scanf("%d",&op);
if(op==1){
FILE* fp=fopen("test.txt","r");
n=ReadIn(fp);
puts("");
fclose(fp);
Freq_stats();
puts("");
HuffmanCoding();
puts("");
fp=fopen("test.comp","wb");
s2.clear();
for(int i=0;i<n;++i){
s2+=anss[s[i]];
}
cout<<"以二进制形式查看该压缩后的文件:"<<"\n"<<s2<<"\n\n";
lenp=0;
int tmp=0;
for(int i=0;i<s2.length();++i){
tmp=tmp*2+s2[i]-'0';
if(i%8==7 || i==s2.length()-1){
sp[lenp++]=tmp;
tmp=0;
if(i==s2.length()-1){
sp[lenp++]=(i+1)%8;
if(!sp[lenp-1]){
sp[lenp-1]=8;
}
}
}
}
uc t[1];
t[0]=m;
fwrite(t,sizeof(uc),1,fp);
for(int i=0;i<m;++i){
fwrite(table+i,sizeof(char),1,fp);
ull tt[1]={0};
for(int j=0;j<anss[table[i]].length();++j){
tt[0]=tt[0]*2+anss[table[i]][j]-'0';
}
char tmp_len[1]; tmp_len[0]=anss[table[i]].length();
fwrite(tmp_len,sizeof(char),1,fp);
fwrite(tt,sizeof(ull),1,fp);
}
fwrite(sp,sizeof(uc),lenp,fp);
fclose(fp);
printf("按任意键继续");
while(!kbhit());
ch=getch();
if(ch==-32){
getch();
}
}
else if(op==2){
FILE* fp=fopen("test.comp","rb");
char M[1];
fread(M,sizeof(char),1,fp);
m=M[0];
memset(cnts,0,sizeof(cnts));
ull anss[256]={0};
char x[1];
ull y[1];
char tlen[1];
map<string,char>ma;
for(int i=1;i<=m;++i){
fread(x,sizeof(char),1,fp);
fread(tlen,sizeof(char),1,fp);
fread(y,sizeof(ull),1,fp);
string ts="";
for(int j=tlen[0]-1;j>=0;--j){
ts+=(char)((y[0]>>j)&1);
}
ma[ts]=x[0];
}
memset(sp,0,sizeof(sp));
fread(sp,sizeof(uc),N,fp);
fclose(fp);
string now="";
FILE* fp2=fopen("test2.txt","w");
int nn;
for(int i=N+4;i>=0;--i){
if(sp[i]){
nn=i;
break;
}
}
puts("解压后的原文本为:");
for(int i=0;i<nn;++i){
int lim=(i==nn-1 ? sp[nn] : 8);
for(int j=0;j<lim;++j){
now+=(char)((sp[i]>>(lim-1-j))&1);
if(ma[now]){
putchar(ma[now]);
fprintf(fp2,"%c",ma[now]);
now.clear();
}
}
}
fclose(fp2);
puts("");
printf("按任意键继续");
while(!kbhit());
ch=getch();
if(ch==-32){
getch();
}
}
else{
break;
}
}
return 0;
}
int ReadIn(FILE* fp){
int len=0;
while(!feof(fp)){
fgets(s+len,N,fp);
len+=strlen(s+len);
}
puts("原文本:");
puts(s);
return len;
}
void Freq_stats(){
m=0;
memset(cnts,0,sizeof(cnts));
for(int i=0;i<n;++i){
++cnts[s[i]];
}
puts("各字符出现频率:");
for(int i=0;i<256;++i){
if(cnts[i]){
table[m++]=(char)i;
if(i!='\n'){
printf("%c %d\n",i,cnts[i]);
}
else{
printf("\\n %d\n",cnts[i]);
}
}
}
}
void dfs(int U,string s){
if(U<256){
anss[U]=s;
}
char c='0';
for(ITER it=G[U].begin();it!=G[U].end();++it,++c){
dfs(*it,s+c);
}
}
void HuffmanCoding(){
for(int i=0;i<512;++i){
G[i].clear();
}
priority_queue<data,vector<data>,greater<data> >Heap;
for(int i=0;i<256;++i){
if(cnts[i]){
Heap.push(make_pair(cnts[i],i));
}
}
for(int i=1;i<m;++i){
data x=Heap.top(); Heap.pop();
data y=Heap.top(); Heap.pop();
G[255+i].push_back(x.second);
G[255+i].push_back(y.second);
sort(G[255+i].begin(),G[255+i].end());
Heap.push(data(x.first+y.first,255+i));
}
dfs(255+m-1,"");
puts("给各个字符分配的零一编码:");
for(int i=0;i<256;++i){
if(cnts[i]){
if(i!='\n'){
cout<<(char)i<<' '<<anss[i]<<endl;
}
else{
cout<<"\\n "<<anss[i]<<endl;
}
}
}
}