#include<iostream>
#include<fstream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=200;
typedef int LL;
typedef struct HTNode* ToNode;
struct HTNode{
LL weight;
LL lson;LL rson;LL father;
char c;
}HT[maxn];///到时候改成动态的
struct Querypos{
LL s1=0;LL s2=0;///第一个为最小,第二个为次小
};
struct Answer{
LL cnt=0;
char bcode[maxn];
}ans[maxn];
char str[maxn];
char txtstr[maxn*maxn];
char outputTxT[maxn];
char choice[maxn];
LL outputnum=0;
LL len=0;
bool vis[maxn];
LL n;
Querypos search(LL l,LL r){
LL minval1=0x3f3f3f3f;LL minval2=0x3f3f3f3f;
LL minpos1=0;LL minpos2=0;
for(LL i=l;i<=r;i++){
if(!vis[i]){
if(minval1>HT[i].weight){
minval2=minval1;
minpos2=minpos1;
minval1=HT[i].weight;
minpos1=i;
}
else if(minval2>HT[i].weight){
minval2=HT[i].weight;
minpos2=i;
}
}
}
Querypos t;
t.s1=minpos1; t.s2=minpos2;
return t;
}
///先考虑建树
void Initialzation(ToNode &now,LL n){
if(n<=1) return;
now=(ToNode)malloc(sizeof(HTNode));///到时候改成动态
LL m=2*n-1;
for(LL i=n+1;i<=m;i++){
Querypos temp=search(1,i-1);///挑选树节点中频率最小的两个权值
LL s1=temp.s1;LL s2=temp.s2;
debug(s1);debug(s2);debug(i);
vis[s1]=true;vis[s2]=true;
HT[s1].father=i;HT[s2].father=i;
HT[i].lson=s1;HT[i].rson=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
}
///从叶子往根搜,没有string的返回值,C语言临时数组能传参嘛0.0
void Encoding(LL now,LL want){
if(HT[now].father){
LL fa=HT[now].father;
if(HT[fa].lson==now){
ans[want].bcode[++ans[want].cnt]='0';
}
else if(HT[fa].rson==now){
ans[want].bcode[++ans[want].cnt]='1';
}
Encoding(HT[now].father,want);
}
}
void Codereverse(LL now){
for(LL i=1,j=ans[now].cnt;i<j;i++,j--){
swap(ans[now].bcode[i],ans[now].bcode[j]);
}
}
LL rebuild(LL rootnow,LL index){///01串还原成字符串,函数体返回当前这个字符01串的长度
if(!HT[rootnow].lson&&!HT[rootnow].rson){
///if(rootnow<=n){
char op;
outputTxT[++outputnum]=HT[rootnow].c;
op=HT[rootnow].c;
cout<<op;
return 0;
}
if(txtstr[index]=='1'){
return 1+rebuild(HT[rootnow].rson,index+1);
}
else if(txtstr[index]=='0'){
return 1+rebuild(HT[rootnow].lson,index+1);
}
}
void writefileTree(LL n){///写出哈夫曼树文件
ofstream app1("hfmTree",ofstream::out);
for(LL i=1;i<=n*2-1;i++){///注意是2*n-1,
app1<<(HT[i].weight)<<endl;
app1<<(HT[i].lson)<<endl;
app1<<(HT[i].rson)<<endl;
app1<<(HT[i].father)<<endl;
app1<<(HT[i].c)<<endl;
}
app1.close();
}
LL readfileTree(){
ifstream iFile("hfmTree",ios::in);
LL res=0;
char tempstr[100];
while(iFile.peek()!=EOF){
if(iFile.fail()) break;
iFile.getline(tempstr,20);
int intStr1=atoi(tempstr);
HT[++res].weight=intStr1;
iFile.getline(tempstr,20);
int intStr2=atoi(tempstr);
HT[res].lson=intStr2;
iFile.getline(tempstr,20);
int intStr3=atoi(tempstr);
HT[res].rson=intStr3;
iFile.getline(tempstr,20);
int intStr4=atoi(tempstr);
HT[res].father=intStr4;
iFile.getline(tempstr,20);
HT[res].c=tempstr[0];
}
iFile.close();
return res;
}
void writeToBeTran(LL length){///写入待翻译的文本
ofstream app1("ToBeTran",ofstream::out);
for(LL i=1;i<=length;i++){
app1<<str[i];
}
app1.close();
}
LL readToBeTran(){
ifstream iFile("ToBeTran",ios::in);
LL res=0;
char tempstr[1000];
while(iFile.peek()!=EOF){
if(iFile.fail()) break;
iFile.getline(tempstr,100);
LL length=strlen(tempstr);
for(LL i=0;i<length;i++){
str[++res]=tempstr[i];
}
}
for(LL i=1;i<=res;i++){
cout<<str[i];
}
cout<<endl;
iFile.close();
debug(res);
return res;
}
void writefileCodeFile(){///写出整体文本01串
ofstream app1("CodeFile",ofstream::out);
for(LL i=1;i<=len;i++){
app1<<(txtstr[i])<<endl;
cout<<(txtstr[i]);
}
cout<<endl;
app1.close();
}
LL readfileCodeFile(){///读取整体文本01串
ifstream iFile("CodeFile",ios::in);
char tempstr[100];
LL res=0;
while(iFile.peek()!=EOF){
if(iFile.fail()) break;
iFile.getline(tempstr,40);
txtstr[++res]=tempstr[0];
}
for(LL i=1;i<=res;i++){
cout<<txtstr[i];
}
cout<<endl;
return res;
}
void writeTextfile(){
ofstream app1("Textfile",ofstream::out);
for(LL i=1;i<=outputnum;i++){
app1<<outputTxT[i];
}
app1.close();
}
int main(void)
{
memset(vis,0,sizeof(vis));
cout<<" 哈夫曼编码器\n";
while(choice[0]!='q'||choice[0]!='Q')
{
n=(readfileTree()+1)/2;///先把存在文件里的哈夫曼树读出来
cout<<"功能: "<<"I(初始化,默认为存好的满字符集)"<<""<<"E(编码)"<<""<<"D(译码)"<<""<<"P(打印)"<<""<<"Q(退出)\n";
cout<<"请输入您要选择的功能:";
cin>>choice;
if(choice[0]=='I'||choice[0]=='i'){///初始化
ToNode L;
memset(HT,0,sizeof(HT));///注意清空
cout<<"请输入字符个数:";
cin>>n;
getchar();
printf("请输入字符:");
for(LL i=1;i<=n;i++) scanf("%c",&HT[i].c);///cin不能读空格,注意这个字符是结构体里的,所以需要结构体的&
printf("请输入字符频度:");
for(LL i=1;i<=n;i++) cin>>HT[i].weight;
Initialzation(L,n);///初始化建哈夫曼树
writefileTree(n);///把哈夫曼树存下
n=(readfileTree()+1)/2;///更新为新的哈夫曼树
cout<<"赫夫曼树已经创建完毕,并且已经放入hfmTree文件中!"<<endl;
}
else if(choice[0]=='E'||choice[0]=='e'){///编码
getchar();
cin.getline(str+1,maxn);///终端输入待翻译的ToBeTran
LL strlength=strlen(str+1);
writeToBeTran(strlength);///将TeBeTran写到文件里
strlength=readToBeTran();///读取ToBeTran的正文
debug(strlength);
for(LL i=1;i<=strlength;i++){///把每个字符转换成哈夫曼编码
for(LL j=1;j<=n;j++){
if(str[i]==HT[j].c){
Encoding(j,i);
break;
}
}
}
for(LL i=1;i<=strlength;i++){
Codereverse(i);///反转01串
}
for(LL i=1;i<=strlength;i++){
for(LL j=1;j<=ans[i].cnt;j++){
cout<<ans[i].bcode[j];
}
cout<<endl;
}
for(LL i=1;i<=strlength;i++){
for(LL j=1;j<=ans[i].cnt;j++){
txtstr[++len]=ans[i].bcode[j];///整体文本01串
}
}
for(LL i=1;i<=len;i++){
cout<<txtstr[i];
}
cout<<endl;
writefileCodeFile();///写入整体文本01串
cout<<"\n编码完毕,并且已经存入CodeFile文件!\n";
}
else if(choice[0]=='D'||choice[0]=='d'){///译码
len=readfileCodeFile();///读取整体文本01串
cout<<endl;
for(LL i=1;i<=len;i++){
cout<<txtstr[i];
}
cout<<endl;
for(LL i=1;i<=len;i++){
LL qiguai=rebuild(n*2-1,i);
debug(qiguai);
i=i+qiguai-1;///译码,从根往下搜,注意循环里还有个i++;
}
cout<<endl;
writeTextfile();///把译码存到Textfile中
cout<<"译码结果已存入Textfile.txt中\n";
}
else if(choice[0]=='P'||choice[0]=='p'){///打印编码文件
cout<<"打印代码文件:"<<endl;
len=readfileCodeFile();///读取整体文本01串
for(LL i=1;i<=len;i++){
cout<<txtstr[i];
if(i!=1&&(i%50)==0) cout<<endl;
}
cout<<endl;
}
else if(choice[0]=='Q'||choice[0]=='q'){
break;
}
else{
cout<<"您没有输入正确的步骤,请重新输入!"<<endl;
}
}
return 0;
}
。