使用哈夫曼编码对文本文件进行压缩。
#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("请输入对应数字选择您想要的功能: "); printf("1.压缩当前目录下的test.txt文件到test.comp,并且输出各字符出现频率以及编码表。 "); printf("2.解压当前目录下的test.comp文件,并且输出原文本到test2.txt。 "); printf("3.退出程序。 "); 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<<"以二进制形式查看该压缩后的文件:"<<" "<<s2<<" "; 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!=' '){ printf("%c %d ",i,cnts[i]); } else{ printf("\n %d ",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!=' '){ cout<<(char)i<<' '<<anss[i]<<endl; } else{ cout<<"\n "<<anss[i]<<endl; } } } }