【问题描述】
用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼码的编/译码系统。
【基本要求】
一个完整的系统应具有以下功能:
(1)I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。
(5)T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示出,同时将此字符形式的哈夫曼树写入文件TreePrint中。
【测试数据】
(1) 用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。
字符 |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
频度 |
64 |
13 |
22 |
32 |
103 |
21 |
15 |
47 |
57 |
1 |
5 |
32 |
20 |
字符 |
N |
O |
P |
Q |
R |
S |
T |
U |
V |
W |
X |
Y |
Z |
频度 |
57 |
63 |
15 |
1 |
48 |
51 |
80 |
23 |
8 |
18 |
1 |
16 |
1 |
【实现提示】
(1) 编码结果以文本方式存储在文件CodeFile中。
(2) 用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”表示退出运行Quit。请用户键入一个选择功能符。此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
(3) 在程序的一次执行过程中,第一次执行I、D或C命令之后,哈夫曼树已经在内存了,不必再读入。每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。
//Huff.h
#include
#include
#include
#include
#include
#define MVNum 26
using namespace std;
typedef struct
{
int weight;
char data;
int parent;
int lchild;
int rchlid;
}HTNode,*HuffTree;
typedef struct
{
char data;
char *code;
}HuffmanCode[MVNum+1];
void swap(int &s1,int &s2)
{
int temp;
temp=s1;
s1=s2;
s2=temp;
}
int Select(HuffTree HT,int n,int &s1,int &s2)
{
int min1=INT_MAX,min2=INT_MAX;
for(int i=1;i<=n;i++)
{//min1>=min2;
if(HT[i].parent==0)
if(HT[i].weight { min1=HT[i].weight; s1=i; if(min1 {//保持min1>=min2 swap(min1,min2); swap(s1,s2); } } } return 1; } int Initialization(HuffTree &HT,int n) { ofstream fout("f:\\TEMPASD\\hfmTree.dat",ios::out|ios::binary); if(n<=1)return 0; int m=2*n-1; HT=new HTNode[m+1]; for(int i=0;i<=m;i++) { HT[i].data='#'; HT[i].parent=0; HT[i].lchild=0; HT[i].rchlid=0; } cout<<"input data&weight"< for(int i=1;i<=n;i++) { cin>>HT[i].data>>HT[i].weight; } /*---------创建哈夫曼树-------*/ int s1,s2; for(int i=n+1;i<=m;i++) { Select(HT,i-1,s1,s2); HT[s1].parent=i;HT[s2].parent=i; HT[i].lchild=s1;HT[i].rchlid=s2; HT[i].weight=HT[s1].weight+HT[s2].weight; } fout.seekp(0,ios::beg); for(int i=0;i<=m;i++) { fout.write(reinterpret_cast<char *>(&(HT[i])),sizeof(HTNode)); } fout.close(); return 1; } int Initialization_1(HuffTree &HT,int n) { ifstream fin("f:\\TEMPASD\\hfmTree.dat",ios::in|ios::binary); if(n<=1)return 0; int m=2*n-1; HT=new HTNode[m+1]; fin.seekg(0,ios::beg); if(fin) { HTNode temp; for(int i=0;i<=m;i++) { fin.read(reinterpret_cast<char *>(&(temp)),sizeof(HTNode)); HT[i]=temp; } } else { cout<<"File could not be open"< return 0; } return 1; } void CreateHuffmanCode(HuffTree &HT,HuffmanCode &HC,int n) { char *cd=new char[n]; if(HT[2*MVNum-1].lchild==0||HT[2*MVNum-1].rchlid==0) {//内存中没有树,需重新添加 Initialization_1(HT,n); } cd[n-1]='\0'; for(int i=1;i<=n;i++) { int start=n-1; int c=i,f=HT[i].parent; HC[i].data=HT[i].data; while(f!=0) { start--; if(HT[f].lchild==c) cd[start]='0'; else cd[start]='1'; c=f;f=HT[f].parent; } HC[i].code=new char[n-start]; strcpy_s(HC[i].code,n-start,&cd[start]); } delete cd; } int Locate(HuffmanCode HC,char ch) { for(int i=0;i<=MVNum;i++) { if(ch==HC[i].data) return i; } return -1; } void Encoding(HuffmanCode HC) { char c;int i; ifstream fin;fin.open("f:\\TEMPASD\\ToBeTran.txt",ios::in); ofstream fout;fout.open("f:\\TEMPASD\\CodeFile.txt",ios::out); if(!fin) { cerr<<"File could not be open!"< abort(); } while(fin.get(c)) { if(c<'A'||c>'Z') continue; i=Locate(HC,c); fout<<HC[i].code; } fin.close(); fout.close(); } void Decoding(HuffTree HT) { char c;int i=2*MVNum-1; ofstream fout("f:\\TEMPASD\\TextFile.txt",ios::out); ifstream fin("f:\\TEMPASD\\CodeFile.txt",ios::in); if(!fin) { cerr<<"File could not be open!"< abort(); } while(fin.get(c)) { if(c=='0') i=HT[i].lchild; else i=HT[i].rchlid; if(HT[i].lchild==0&&HT[i].rchlid==0) { fout<<HT[i].data; i=2*MVNum-1; } } fout<<'\n'; fout.close(); fin.close(); } void Print(HuffmanCode HC) { char c;int flag=1; ifstream fin("f:\\TEMPASD\\CodeFile.txt",ios::in); ofstream fout("f:\\TEMPASD\\CodePrin.txt",ios::out); while(fin.get(c)) { cout< if(flag==50) { cout< fout<<'\n'; flag=1; } } } void printhelp(HuffTree &HT,string ss,int num) { if(HT[num].lchild<=0&&HT[num].rchlid<=0) { ss+=" "; cout<<ss<<HT[num].data< return; } ss+=" "; printhelp(HT,ss,HT[num].rchlid); cout<<ss<<HT[num].data< printhelp(HT,ss,HT[num].lchild); } void Tree_printing(HuffTree &HT) { if(HT[2*MVNum-1].lchild==0||HT[2*MVNum-1].rchlid==0) Initialization_1(HT,MVNum); string ss=""; printhelp(HT,ss,2*MVNum-1); } //源.cpp #include"Huff.h" int main() { HuffTree HT=new HTNode[2*MVNum];int flag=1;char ch; HuffmanCode HC; for(int i=0;i<=2*MVNum-1;i++) { HT[i].data='#'; HT[i].parent=0; HT[i].lchild=0; HT[i].rchlid=0; } while(1) { cout<<"-----------哈夫曼编/译码器-----------"< cout<<"-----------I.初始化------------------"< cout<<"-----------E.编码--------------------"< cout<<"-----------D.译码--------------------"< cout<<"-----------P.印代码文件--------------"< cout<<"-----------T.印哈夫曼树--------------"< cout<<"-----------Q.退出程序----------------"< cin>>ch; switch(ch) { case 'I':Initialization(HT,MVNum);break; case 'E':CreateHuffmanCode(HT,HC,MVNum);Encoding(HC);break; case 'D':Decoding(HT);break; case 'P':Print(HC);break; case 'T':Tree_printing(HT);break; case 'Q':flag=0;break; default:break; } if(flag==0) break; } return 0; }