在一个加密应用中,要处理的信息来自下面的字符集,各个字符的相关使用频度如下:
字符空格 A B C D E F G H I J K L M
频度 180 64 13 23 32103 22 15 47 57 1 5 31 20
字符 N O P Q R S T U V W X Y Z
频度 55 63 15 1 48 56 80 25 7 18 2 16 1
现请编写程序你实现如下功能:
(1)运行时,由用户输入来初始化字符集大小和相应用字符。
(2)输入一个要加密的字符串,将其加密。
(3)输出解密字符串。
二、 需求分析
哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算机信息处理中, 哈弗曼编码在信息论中应用举例 “哈夫曼编码”是一种一致性编码法(又称“熵编码法”),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。
这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。这种方法是由David.A.Huffman发展起来的。
例如,在英文中,e的出现概率很高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个位 哈弗曼编码在信息论中应用举例[2] (bit)来表示,而z则可能花去25个位(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个位。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。若能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。
因此,对于哈夫曼编码如何实现的理解是非常有用与重要的。
三、功能
(1)用户自行输入相对的字符与其权值,程序构造哈夫曼树。
(2)输出根据由用户输入数据与权值生成的哈夫曼编码。
(3)输入字符转换成哈夫曼编码。
(4)输入哈夫曼编码转换成字符。
四、收获和不足之处
在这一次的课程设计中,接触的东西比以前所做过的程序设计更加有难度,更有挑战。我觉得数据结构首先得能理解,理解书本上知识,这是第一步。然后接下来要把对书本上知识生硬的理解在实际操作中转换成自己的经验,这样子才能理解更深,同时也不容易忘记。
这一次的课程设计里,我做课题是哈夫曼树,一开始我以为很简单,以为接收用户输入的字符和权值,构造哈夫曼树,再进行编码解码就可以了。结果当我真正开始做的时候,才发现我想的太简单了。看起来挺简单易懂的思想,当要我在代码里实现的时候却是举步维艰。直到最后我对于程序中的一些部分还是懵懵懂懂的。这警醒我在今后的学习中得注意实践,认真对待任何事情,不管看起来是不是很简单。
五、程序截图
六、源代码
#include<iostream.h>
#include<string.h>
#include<fstream.h>
#define Maxbit 20
#define Maxvalue 10000
#define Maxleaf 20
#define Maxnode Maxleaf*2-1
typedef struct {
int weight;
int parent;
int lchild;
int rchild;
}Hnodetype;
typedef struct{
int bit[Maxbit];
int start;
}Hcodetype;
int n=0;
char HT[26][2];
void inputfun(Hnodetype huffnode[Maxnode])//输入叶子节点的个数及权值:初始化函数
{
int i;
char zifu[10];
ofstream in;
in.open("data1.txt",ios::trunc);
cout<<"请输入叶子节点的个数";
cin>>n;
while(n<=0||n>20)
{
cout<<"输入错误,请重新输入";
cin>>n;
}
in<<n<<"\n";
for(i=0;i<2*n-1;i++)
{
huffnode[i].weight=0;
huffnode[i].parent=-1;
huffnode[i].lchild=-1;
huffnode[i].rchild=-1;
}
cout<<"请分别输入这"<<n<<"个叶子节点的字符名称及权值";
for(i=0;i<n;i++)
{
cout<<endl<<"字符-";
cin>>zifu[i];
in<<zifu[i]<<" ";
cout<<" 权重-";
cin>>huffnode[i].weight;
in<<huffnode[i].weight<<"\n";
}
in.close();
}
void creattree(Hnodetype *huffnode)//哈夫曼树的建立
{
int m1,m2,x1,x2,n;
int i,j;
fstream out1;
out1.open("data1.txt",ios::in);
out1>>n;
out1.close();
for(i=0;i<n-1;i++)
{
m1=m2=Maxvalue;
x1=x2=0;
for(j=0;j<n+i;j++)
{
if(huffnode[j].parent==-1&&huffnode[j].weight<m1)
{
m2=m1;
x2=x1;
m1=huffnode[j].weight;
x1=j;
}
else
if(huffnode[j].parent==-1&&huffnode[j].weight<m2)
{
m2=huffnode[j].weight;
x2=j;
}
}
huffnode[x1].parent=n+i;
huffnode[x2].parent=n+i;
huffnode[n+i].weight=huffnode[x1].weight+huffnode[x2].weight;
huffnode[n+i].lchild=x1;
huffnode[n+i].rchild=x2;
}
ofstream in;
in.open("data2.txt",ios::trunc);
for(i=0;i<2*n-1;i++)
{
in<<huffnode[i].weight<<" "
<<huffnode[i].lchild<<" "
<<huffnode[i].rchild<<" "
<<huffnode[i].parent<<"\n";
}
in.close();
}
void codefun()//哈夫曼编码函数
{
Hcodetype cd;
Hcodetype huffcode[Maxleaf];
Hnodetype huffnode[Maxnode];
int i,j,c,p,n;
fstream out1;
out1.open("data1.txt",ios::in);
out1>>n;
out1.close();
fstream out2;
out2.open("data2.txt",ios::in);
for(i=0;i<2*n-1;i++)
{
out2>>huffnode[i].weight
>>huffnode[i].lchild
>>huffnode[i].rchild
>>huffnode[i].parent;
}
for(i=0;i<n;i++)
{
cd.start=n-1;
c=i;
p=huffnode[i].parent;
while(p!=-1)
{
if(huffnode[p].lchild==c)
cd.bit[cd.start]=0;
else
cd.bit[cd.start]=1;
cd.start--;
c=p;
p=huffnode[c].parent;
}
for(j=cd.start+1;j<n;j++)
{
huffcode[i].bit[j]=cd.bit[j];
huffcode[i].start=cd.start;
}
}
out2.close();
ofstream in;
in.open("data3.txt",ios::trunc);
for(i=0;i<n;i++)
{
in<<huffcode[i].start<<" ";
for(int j=huffcode[i].start+1;j<n;j++)
in<<huffcode[i].bit[j]<<" ";
in<<endl;
}
in.close();
}
void outputcode()//输出哈夫曼编码:形式为A--010
{
char s;
int w;
int m,b,d;
fstream out1;
out1.open("data1.txt",ios::in);
fstream out2;
out2.open("data3.txt",ios::in);
out1>>m;
for(int c=0;c<m;c++)
{
out1>>s>>w;
cout<<s<<"--";
HT[c][0]=s;
out2>>b;
for(int r=b+1;r<m;r++)
{
out2>>d;
cout<<d;
HT[c][1]=d;
}
cout<<endl;
}
out1.close();
out2.close();
}
void encode()//哈夫曼解码函数
{
char a[100];
char zifu[30];
int len,cc,n,w;
int j=0;
int p,c=0,mm;
Hnodetype huffnode[Maxnode];
Hcodetype huffcode[Maxleaf];
fstream out1;
out1.open("data1.txt",ios::in);
out1>>n;
for(int v=0;v<n;v++) out1>>zifu[v]>>w;
out1.close();
fstream out2;
out2.open("data2.txt",ios::in);
for(v=0;v<2*n-1;v++)
{
out2>>huffnode[v].weight
>>huffnode[v].lchild
>>huffnode[v].rchild
>>huffnode[v].parent;
}
out2.close();
fstream out3;
out3.open("data3.txt",ios::in);
for(v=0;v<n;v++)
{
out3>>huffcode[v].start;
for(int u=huffcode[v].start+1;u<n;u++)
out3>>huffcode[v].bit[u];
}
out3.close();
ofstream in;
in.open("data4.txt",ios::trunc);//ios::trunc表示在打开文件前将文件清空,文件不存在则创建
cout<<"请输入一串二进制编码"<<endl;
cin>>a;
len=strlen(a);
p=huffnode[c].parent;
while(p!=-1)
{
c++;
p=huffnode[c].parent;
}//求树中结点的总数目为c,根节点在huffnode[]中的下表地址为c
cc=c;//记录当前的下表地址
cout<<"译码结果为";
for(int i=0;i<len;i++)
{
if(a[i]=='0') cc=huffnode[cc].lchild;
else if(a[i]=='1') cc=huffnode[cc].rchild;
if(huffnode[cc].lchild==-1&&huffnode[cc].rchild==-1)//从j到i为一个字符的编码
{
for(int k=0;k<n;k++)
{
mm=huffcode[k].start+1;
for(int hh=j;hh<=i,mm<n;hh++,mm++)
{
if((a[hh]-'0')!=huffcode[k].bit[mm]) break;
}
if(hh>=i&&mm==n)
{
cout<<zifu[k];
in<<zifu[k];
j=i+1;
cc=c;//更新j和cc的值
break;
}
}
}
}
in.close();
}
int main()
{
int m,n;
Hnodetype huffnode[Maxnode];
cout<<endl<<"---------------哈夫曼编译码系统---------------"<<endl;
cout<<" 1.建立哈夫曼树"<<endl
<<" 2.输出哈夫曼编码"<<endl
<<" 3.进行哈夫曼译码"<<endl
<<" 4.进行哈夫曼编码"<<endl
<<" 0.退出"<<endl
<<"请选择:";
cin>>m;
while(m<0||m>4)
{
cout<<"输入错误,请重新输入";
cin>>m;
}
while(m)
{
fstream out1;
out1.open("data1.txt",ios::in);
out1>>n;
out1.close();
if(m==1)
{
inputfun(huffnode);
creattree(huffnode);
codefun();
}
else if(m==2)
{
if(n==0)
{
cout<<"请先初始化,建立哈夫曼树"<<endl;
}
else
{
cout<<endl<<"输出哈夫曼树的各个字符的编码为"<<endl;
outputcode();
}
}
else if(m==3)
{
if(n==0)
{
cout<<"请先初始化,建立哈夫曼树"<<endl;
}
else
{
encode();
cout<<endl;
}
}
else if(m==4)
{
if(n==0)
{
cout<<"请先初始化,建立哈夫曼树"<<endl;
}
else
{
int d;
cout<<"请输入要翻译的字符串长度:";
cin>>d;
char *c=new char[d];
cout<<"请输入字符串";
for(int i=0;i<d;i++)
cin>>c[i];
cout<<"编码为";
for(i=0;i<d;i++)
{
for(int q=0;q<26;q++)
{
if(HT[q][0]==c[i])
{
cout<<HT[q][1];
}
}
}
}
}
cout<<endl<<"返回主菜单为"<<endl;
cout<<endl<<"---------------哈夫曼编译码系统----------------"<<endl;
cout<<" 1.建立哈夫曼树"<<endl
<<" 2.输出哈夫曼编码"<<endl
<<" 3.进行哈夫曼译码"<<endl
<<" 4.进行哈夫曼编码"<<endl
<<" 0.退出"<<endl
<<"请选择:";
cin>>m;
while(m<0||m>4){
cout<<"输入错误,请重新输入";
cin>>m;
}
}
return 0;
}