- 问题描述
利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个赫夫曼码的编/译码系统。 - 基本要求
一个完整的系统应具有以下功能:
(1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。
(2) E:编码(Encoding)。利用已建好的赫夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3) D:译码(Decoding)。利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。
#include<bits/stdc++.h>
#include <fstream>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#define INF 0x7fffffff
#define EPS 1e-12
#define MOD 1000000007
#define PI 3.141592653579798
#define N 100000
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
map<char,string> kt;//保存字符与编码的对应关系
struct htnode
{
int wei;
char c;
htnode *parent,*lch,*rch;
htnode(char a='.',int b=0):c(a),wei(b)//构造函数
{
parent=lch=rch=NULL;
}
};
struct cmp
{
bool operator()(htnode const *a,htnode const *b)
{
return a->wei>b->wei;
}
};//按照结构体的权值排序
htnode* hufuman(htnode q[],int n)//用最小优先队列建哈夫曼树
{
priority_queue<htnode*,vector<htnode*>,cmp>st;//最小优先队列
for(int i=0;i<n;i++)
{
st.push(&q[i]);
}
while(st.size()>1)
{
htnode *x,*y;
x=st.top();
st.pop();
y=st.top();
st.pop();
htnode* z=new htnode('0',x->wei+y->wei);
z->lch=x;z->rch=y;
x->parent=y->parent=z;
st.push(z);
if(st.size()==1)break;
}//每次选出两个最小的节点组成新的节点放入队列中
return st.top();
}
void dfs(htnode* v,string s)//一次遍历得到哈夫曼编码保存在容器kt中左1
{
if(v->lch==NULL&&v->lch==NULL)
{
kt[v->c]=s;return;
}
string ss=s;
ss+='1';//左儿子边为1
dfs(v->lch,ss);
ss=s;ss+='0';//右为儿子边为0
dfs(v->rch,ss);
}
string zhuanyi(char s[])//把输入的字符文本转译为哈夫曼编码
{
int len=strlen(s);
// cout<<len<<endl;
string ans="";
for(int i=0;i<len;i++)
{
ans+=kt[s[i]];
}
FILE *fp;
fp=fopen("CodeFile.txt","w");
for(int i=0;i<ans.size();i++)
{
fprintf(fp,"%c",ans[i]);//把转译之后的哈夫曼码写入文件中
}
if(fclose(fp))
{
printf("关闭文件失败\n");
exit(0);
}
return ans;
}
void get_c(htnode* v,string s,int &i,string &ans)//根据哈夫曼树找到对应字符
{
if(v->lch==NULL&&v->rch==NULL)
{
ans+=v->c;
return ;
}
if(s[i]=='1')
{
get_c(v->lch,s,++i,ans);
}
else
{
get_c(v->rch,s,++i,ans);
}
}
void Decoding(htnode *root)//从文本中读入哈夫曼编码并转译成文本
{
string tmp="",ans="";char ch;
FILE *fp1,*fp2;
if((fp1=fopen("CodeFile.txt","r"))==NULL)
{
printf("打开文件失败\n");
exit(0);
}
while(!feof(fp1))
{
ch=fgetc(fp1);//读入哈夫曼编码
tmp+=ch;
}
if(fclose(fp1))
{
printf("关闭文件失败\n");
exit(0);
}
int i=0;
while(i<tmp.size())
{
get_c(root,tmp,i,ans);//转译字符
}
cout<<ans<<endl;
fp2=fopen("Textfile.txt","w");
for(int i=0;i<ans.size()-1;i++)
{
fprintf(fp2,"%c",ans[i]);//转译之后的文本写入文件
}
for(int i=0;i<ans.size()-1;i++)
{
cout<<ans[i];
}
cout<<endl;
if(fclose(fp2))
{
printf("关闭文件失败\n");
exit(0);
}
}
void ddfs(htnode* v,FILE* fp)//遍历哈夫曼树来得到权值和左右儿子
{
if(v->lch==NULL&&v->rch==NULL)
{
cout<<v->c<<" "<<v->wei<<endl;
fprintf(fp,"%c\t\t%d\n",v->c,v->wei);
return ;
}
htnode *t,*tt;
t=v->lch;tt=v->rch;
cout<<v->c<<"\t\t"<<v->wei<<"\t\t"<<t->wei<<"\t\t"<<tt->wei<<endl;
fprintf(fp,"%c\t\t%d\t\t%d\t\t%d",v->c,v->wei,t->wei,tt->wei);
ddfs(v->lch,fp);
ddfs(v->rch,fp);
}
void puts(htnode* root)//打印哈夫曼树并保存到文本中
{
FILE* fp;
fp=fopen("hfm.txt","w");
cout<<"哈夫曼树"<<endl;
cout<<"字符\t\t权值\t\t左儿子权值\t\t右儿子权值"<<endl;
ddfs(root,fp);
if(fclose(fp))
{
printf("关闭失败\n");
exit(0);
}
}
int main()
{
int op,n;htnode *root;
cout<<"请输入字符个数"<<endl;
cin>>n;
htnode *ht=new htnode[n];
cout<<"请输入字符以及其所对应的次数"<<endl;
for(int i=0;i<n;i++)
{
getchar();
scanf("%c %d",&ht[i].c,&ht[i].wei);
}
root=hufuman(ht,n);dfs(root,"");
map<char,string>::iterator it=kt.begin();
while(it!=kt.end())
{
cout<<it->first<<" "<<it->second<<endl;
it++;
}
puts(root);
cout<<"请输入你要转换的文章"<<endl;
char s[1000];
getchar();
gets(s);
cout<<zhuanyi(s)<<endl;
Decoding(root);
}
下面是实验报告
链接:https://pan.baidu.com/s/1o8ooop8 密码:bk75