哈夫曼编码数据结构C++程序.docx
《哈夫曼编码数据结构C++程序.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码数据结构C++程序.docx(15页珍藏版)》请在冰豆网上搜索。
![哈夫曼编码数据结构C++程序.docx](https://file1.bdocx.com/fileroot1/2022-12/12/6ebf27fe-fd3d-48be-ac5b-b5ac8c1a0df2/6ebf27fe-fd3d-48be-ac5b-b5ac8c1a0df21.gif)
哈夫曼编码数据结构C++程序
数据结构课程设计
一、目的
《数据结构》是一门实践性较强的软件基础课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。
本课程设计的目的就是要达到理论与实际应用相结合,使同学们能够根据数据对象的特性,学会数据组织的方法,能把现实世界中的实际问题在计算机内部表示出来,并培养基本的、良好的程序设计技能。
二、要求
通过这次设计,要求在数据结构析逻辑特性和物理表示,数据结构的选择的应用、算法的设计及其实现等方面中深对课程基本内容的理解。
同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。
三、内容
2.哈夫曼编码/译码器
【问题描述】
设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。
【基本要求】
(1)初始化:
键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;
(2)编码:
利用建好的哈夫曼树生成哈夫曼编码;
(3)输出编码;
(4)设字符集及频度如下表:
字符空格ABCDEFGHIJKLM
频度1866413223210321154757153220
字符NOPQRSTUVWXYZ
频度5763151485180238181161
【选做内容】
(1)译码功能;
(2)显示哈夫曼树;
(3)界面设计的优化。
哈夫曼编写编译码
一、问题描述
利用哈夫曼编码进行通信可以大大提高信道利用率,这要求在发送端通过一个编码系统对待传输预先编码,在接收端将传来的数据进行译码。
对于双工通道,每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
二、概要设计
1.哈夫曼树的定义:
在一棵二叉树中,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。
2.哈夫曼树的构造:
假设有N个权值,则构造出的哈夫曼树有N个叶子结点。
N个权值分别设为W1,W2,……….Wn,则哈夫曼树的构造规则为:
(1)将W1,W2,……….Wn看成有N棵树的森林;
(2)在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左,右子树,且新树的根结点为其左,右子树结点权值之和;
(3)从森林中删除选取取的两面三刀棵树,并将新树加入森林;
(4)重复
(2)(3)步,直到森林中只剩一棵树为止,该树即为我们所求得的哈夫曼树。
在构造哈夫曼树的过程中,每次由两棵权值最小的树生成一棵新树时,新树的左子树和右子树可以任意安排,这样将会得到具有不同结构的多个哈夫曼树,但字们都具有相同的带权路径长度。
为了歙 得到的哈夫曼树的结构尽量唯一,通常规定生成的哈夫曼树中每个结点的左子树根结点的权要小于等于右女树根结点的权。
3.构造哈夫曼树的算法实现:
假设哈夫曼树采用双亲孩子表示法存储,并增加权值域,构造哈夫曼树的叶子结点(树木的权)有N个,合并次数为N—1次,则森林中总共有2N—1棵树,(包含合并后删除的)。
存储结构描述为:
constintn=maxn//maxn表示叶子数目
constintm=2*n-1//m为森林中树的棵数
classtree
{public:
floatweight;//权值
intparent;//双亲
intlch,rch;//左,右孩子
}
treehftree[m+1];//规定从第一个元素hftree[1]开始使用数组元素,故定义长度为m+1而不为m
4.结构类型:
typedefstruct
{
chardata;
intweight;
intparent;
intlchild;
intrchild;
}huffnode;
typedefstruct
{
charcd[MAX];
intstart;
}huffcode;
5.主程序
intmain()
{
初始化:
输入字符代码以及权值.
编制哈夫曼码:
根据权值建立二叉树,输出相应的根节点到叶结点的路
径,便是哈夫曼编码.
编码:
输入字符,输出哈夫曼码.
译码:
输入哈夫曼,输出字符代码.
退出:
结束进程,退出程序.
return0;
}
三、详细设计
#include
#include
#include
#defineMAX25
typedefstruct
{
chardata;
intweight;
intparent;
intlchild;
intrchild;
}HTNode;
typedefstruct
{
charcd[MAX];
intstart;
}HuffmanCode;
intmain()
{
HTNodeht[2*MAX];
HuffmanCodehcd[MAX],d;
inti,k,f,l,r,n,c,s1,s2;
cout<<"*********************\n"
<<"\t哈夫曼编码与译码系统\n"
<<"*********************\n";
cout<<"\n请输入哈夫曼码元素个数:
";
cin>>n;
cout<<"请输入各个元素的结点值与权值:
\n";
for(i=1;i<=n;i++)
{
cout<<"第"<\n\t结点值:
";
cin>>&ht[i].data;
cout<<"\t权值:
";
cin>>ht[i].weight;
}
for(i=1;i<=2*n-1;i++)
ht[i].parent=ht[i].lchild=ht[i].rchild=0;
for(i=n+1;i<=2*n-1;i++)
{
s1=s2=32767;
l=r=0;
for(k=1;k<=i-1;k++)
if(ht[k].parent==0)
if(ht[k].weight{
s2=s1;
r=l;
s1=ht[k].weight;
l=k;
}
elseif(ht[k].weight{
s2=ht[k].weight;
r=k;
}
ht[l].parent=i;
ht[r].parent=i;
ht[i].weight=ht[l].weight+ht[r].weight;
ht[i].lchild=l;
ht[i].rchild=r;
}
for(i=1;i<=n;i++)
{
d.start=n+1;
c=i;
f=ht[i].parent;
while(f!
=0)
{
if(ht[f].lchild==c)
d.cd[--d.start]='0';
else
d.cd[--d.start]='1';
c=f;
f=ht[f].parent;
}
hcd[i]=d;
}
cout<<"输出哈夫曼编码:
\n";
for(i=1;i<=n;i++)
{
cout<";
for(k=hcd[i].start;k<=n;k++)
cout<cout<<"\n";
}
l:
cout<<"\n请选择编码/译码/退出系统:
(B/Y/E):
";
charhfm;
cin>>hfm;
if(hfm=='e')
return0;
else
{
switch(hfm)
{
case'b':
{
intq;
charbs;
cout<<"\n***哈夫曼编码***\n";
cout<<"请输入字符代码:
"<for(q=0;bs!
=10;q++)
{
bs=getchar();
for(i=1;i<=n;i++)
{
if(bs==ht[i].data)
for(k=hcd[i].start;k<=n;k++)
cout<}
}
cout<}break;
case'y':
{
chare;
intt,u;
t=2*n-1;
cout<<"\n***哈夫曼译码***\n";
cout<<"\n请输入哈夫曼码:
"<for(u=0;e!
=10;u++)
{
if(ht[t].lchild!
=0)
{
e=getchar();
if(e=='0')
t=ht[t].lchild;
else
t=ht[t].rchild;
}
else
{
cout<t=2*n-1;
}
}
cout<}break;
}
gotol;
}
return0;
}//Huffman
四、编写程序过程中遇到的问题
在编写程序过程中觉得还不够熟练,还是遇到些问题
在编写的程序中还有个问题不能解决,就是编码,译码,退出程序只能运行一次,第二次就不能运行了。
想了很久还是不能解决。
五、设计和调试分析
1.采用一维数组存储结点,构建哈夫曼二叉树.
2.本程序时间复杂为O(n*n):
六、运行结果
1.本程序的运行环境为WS_DOS系统,执行文件为:
ZRC.exe.
2.进入程序后输入字符个数,输入字符及权值,然后选择编码/译码/退出.选编码,输入字符,便输出哈夫曼码;选译码,输入哈夫曼码,输出字符代码;选退出,结束进程,退出程序.
3.用户界面(附调试结果).
*********************
哈夫曼编码与译码系统
*********************
请输入哈夫曼码元素个数:
4
请输入各个元素的结点植与权植:
第1个元素—>
结点植:
1
权植:
10
第2个元素—>
结点植:
3
权植:
13
第3个元素—>
结点植:
5
权植:
12
第4个元素—>
结点植:
4
权植:
15
输出哈夫曼编码:
1:
00
3:
10
5:
01
4:
11
请选择编码/译码/退出系统:
:
y
***哈夫曼编码***
请输入哈夫曼码:
00
1
请选择编码/译码/退出系统:
:
b
***哈夫曼编码***
请输入字符代码:
1
00
请选择编码/译码/退出系统:
:
e
pressanykeytocontinue
七.实验心得
在通信中,可以采用0,1的不同排列来表示不同的字符,称为二进制编码。
而哈夫曼树在数据中的应用,是数据库的最小冗余编码问题,字是数据压缩学的基础。
若每个字符出现的频率相同,则可以采用等长的二进制编码,若频率不同,则可以采用不等长的二进制编码,频率较大的字符采用位数较少的编码,频率较小的字符采用位数较多的编码,这样可以使字符的整体编码长度最小,这就是最小冗余编码问题。
而哈夫曼编码就是一种不等长的二进制编码,且哈夫曼树是一种最优二叉树,它的编码也是一种最优编码,在哈夫曼树中,规定往左编码为0,往右编码为1,则得到叶子结点编码为从根结点到叶子结点中所有路径中0和1的顺序排列。
为了使不等长编码成为无前缀编码,避免译码时的二义性,可用该字符集中的每个字符作为叶子结生成一棵编码二叉树,为了获得传送电文的最短长度,可以将每个字符的出现频率作为字符结点的权值赋予该结点上,求出此树的最小带权路径长度就等于求出了传送电文的最短长度。
因此,求传送电文的最短长度问题就转化为求由集中的所有字符作为叶子结点为,由字符的出现频率作为其权值所产生的哈夫曼权的问题。
通过这次的实验我对软件设计有了一定的了解,同时感觉到自己还有很多的不足之处,特别是实际动手能力还有待于提高。
在以后的学习中,要勤于思考,多动脑,多动手,这样才能不断提高成绩。
附录:
程序源代码
#include
#include
#include
#defineMAX25
typedefstruct
{
chardata;
intweight;
intparent;
intlchild;
intrchild;
}HTNode;
typedefstruct
{
charcd[MAX];
intstart;
}HuffmanCode;
intmain()
{
HTNodeht[2*MAX];
HuffmanCodehcd[MAX],d;
inti,k,f,l,r,n,c,s1,s2;
cout<<"*********************\n"
<<"\t哈夫曼编码与译码系统\n"
<<"*********************\n";
cout<<"\n请输入哈夫曼码元素个数:
";
cin>>n;
cout<<"请输入各个元素的结点值与权值:
\n";
for(i=1;i<=n;i++)
{
cout<<"第"<\n\t结点值:
";
cin>>&ht[i].data;
cout<<"\t权值:
";
cin>>ht[i].weight;
}
for(i=1;i<=2*n-1;i++)
ht[i].parent=ht[i].lchild=ht[i].rchild=0;
for(i=n+1;i<=2*n-1;i++)
{
s1=s2=32767;
l=r=0;
for(k=1;k<=i-1;k++)
if(ht[k].parent==0)
if(ht[k].weight{
s2=s1;
r=l;
s1=ht[k].weight;
l=k;
}
elseif(ht[k].weight{
s2=ht[k].weight;
r=k;
}
ht[l].parent=i;
ht[r].parent=i;
ht[i].weight=ht[l].weight+ht[r].weight;
ht[i].lchild=l;
ht[i].rchild=r;
}
for(i=1;i<=n;i++)
{
d.start=n+1;
c=i;
f=ht[i].parent;
while(f!
=0)
{
if(ht[f].lchild==c)
d.cd[--d.start]='0';
else
d.cd[--d.start]='1';
c=f;
f=ht[f].parent;
}
hcd[i]=d;
}
cout<<"输出哈夫曼编码:
\n";
for(i=1;i<=n;i++)
{
cout<";
for(k=hcd[i].start;k<=n;k++)
cout<cout<<"\n";
}
l:
cout<<"\n请选择编码/译码/退出系统:
(B/Y/E):
";
charhfm;
cin>>hfm;
if(hfm=='e')
return0;
else
{
switch(hfm)
{
case'b':
{
intq;
charbs;
cout<<"\n***哈夫曼编码***\n";
cout<<"请输入字符代码:
"<for(q=0;bs!
=10;q++)
{
bs=getchar();
for(i=1;i<=n;i++)
{
if(bs==ht[i].data)
for(k=hcd[i].start;k<=n;k++)
cout<}
}
cout<}break;
case'y':
{
chare;
intt,u;
t=2*n-1;
cout<<"\n***哈夫曼译码***\n";
cout<<"\n请输入哈夫曼码:
"<for(u=0;e!
=10;u++)
{
if(ht[t].lchild!
=0)
{
e=getchar();
if(e=='0')
t=ht[t].lchild;
else
t=ht[t].rchild;
}
else
{
cout<t=2*n-1;
}
}
cout<}break;
}
gotol;
}
return0;
}//ZRC