南邮数据结构上机实验二二叉树的基本操作及哈夫曼编码译码系统的实现课案Word文档下载推荐.docx
- 文档编号:16237206
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:48
- 大小:385.13KB
南邮数据结构上机实验二二叉树的基本操作及哈夫曼编码译码系统的实现课案Word文档下载推荐.docx
《南邮数据结构上机实验二二叉树的基本操作及哈夫曼编码译码系统的实现课案Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《南邮数据结构上机实验二二叉树的基本操作及哈夫曼编码译码系统的实现课案Word文档下载推荐.docx(48页珍藏版)》请在冰豆网上搜索。
2.核心算法
程序利用循环队列SeqQueue类通过不断出队并输出节点的值,将左右孩子入队直到队列为空实现二叉树的层次遍历。
并运用后序遍历思想,将二叉树树分解为左右子树和根结点,利用(p->
lChild)和(p->
rChild)计算结点数目,并通过交换结点的左右子树实现左右交换,计算树的高度,最后删除二叉树。
核心算法主要是二叉树BinaryTree类中的High,Node_num,Exchange,Level_traversal四个函数,其设计流程图如下:
High()
Node_num()
Exchange()
Level_traversal()
四、程序代码
template<
classT>
intBinaryTree<
T>
:
Node_num(BTNode<
*p)//叶子结点
{
if(p)
{
if(p->
lChild==NULL&
&
p->
rChild==NULL)
return1;
else
returnNode_num(p->
lChild)+Node_num(p->
rChild);
}
return0;
}
voidBinaryTree<
Exchange(BTNode<
*&
t)//左右子树交换
if(t)
BTNode<
*q=t->
lChild;
t->
lChild=t->
rChild;
rChild=q;
Exchange(t->
lChild);
Level_traversal(void(*Visit)(T&
x))//层次遍历
Level_traversal(Visit,root);
cout<
<
endl;
x),BTNode<
*t)//层次遍历
BTNode<
*a;
Visit(t->
element);
if(t->
lChild)
s.EnQueue(t->
rChild)
while(s.Front(a)==true)
if(a->
s.EnQueue(a->
if(a->
Visit(a->
s.DeQueue();
五、测试和调试
1.测试用例和结果
测试结果如下图
2.
结果分析
1)程序能够正确的实现二叉树的基本的建立、删除、复制、遍历以及结点计算等基本操作。
2)由测试结果来看,可以在输出数据时以二叉树图形的形式输出,更简单直观,因此程序还有待改进。
哈夫曼编码和译码系统
所设计的系统重复显示以下菜单项:
B―――建树:
读入字符集和各字符频度,建立哈夫曼树。
T―――遍历:
先序和中序遍历二叉树。
E―――生成编码:
根据已建成的哈夫曼树,产生各字符的哈夫曼编码。
C―――编码:
输入由字符集中字符组成的任意字符串,利用已生成的哈夫曼编码进行编码,显示编码结果,并将输入的字符串及其编码结果分别保存在磁盘文件textfile.txt和codefile.txt中。
D―――译码:
读入codefile.txt,利用已建成的哈夫曼树进行译码,并将译码结果存入磁盘文件result.txt中。
P―――打印:
屏幕显示文件textfile.txt、codefile.txt和result.txt。
X―――退出。
文件Huffman.cpp中定义了四个类,分别是优先权队列类PrioQueue和结点类BTNode、二叉树类BinaryTree以及哈夫曼树类HfmTree,其中哈夫曼树类HfmTree继承了二叉树类BinaryTree。
主函数mian的代码如图所示:
1.类和类的层次结构
程序定义了优先权队列类PrioQueue存储元素,为便于实哈夫曼树的建树运算,定义了哈夫曼树类HfmTree是二叉树类BinaryTree的派生类,新增私有的数据成员weight保存二叉树根的权值。
成员函数getW和putW用于存取该值。
定义了类之后,通过函数Make_Ht建树,将相应的字符和权值录入。
通过遍历哈夫曼树,产生每个叶子节点的哈夫曼编码,当遍历访问某个叶节点是,从该结点到根的路径可以确定该叶结点所代表的字符的编码。
实现译码时,首先将字符读入一维数组,根据0或1向左走向右走直到叶子结点,并将结果写入文件中。
其中关键函数编码code和译码Compile以及打印Print的流程图如下。
code()
下接下一页
Compile
Print()
四、程序代码
HfmTree<
int>
Ht;
intnum;
voidMake_Ht()
charstr[100];
intweight[100];
"
请输入字符个数:
"
;
cin>
>
num;
//建树
请输入权值:
for(inti=0;
i<
i++)
cin>
weight[i];
请输入相应字符集:
str;
Ht=CreateHfmTree(weight,str,num);
voidTraversal_Ht()
{
Ht.PreOrder(Visit);
Ht.InOrder(Visit);
}
Create_code()
Create_code(root);
Create_code(BTNode<
*t)
if(t->
parent)
{
for(intj=0;
j<
=i;
j++)
t->
z[j]=t->
parent->
z[j];
//复制双亲的编码域
i++;
t->
z[i]=t->
val;
//在编码域中加入自己的编码
}
Create_code(t->
//递归,先左孩子,再右孩子
i--;
Create_code_out()//生成编码并输出
Create_code_out(root);
Create_code_out(BTNode<
lChild==t->
rChild)//叶子结点
cout<
t->
ch<
//输出叶子结点中的字符
inti=0;
while(t->
z[i]!
=-1)
{
z[i];
//输出编码域
i++;
}
Create_code_out(t->
lChild);
rChild);
Code()
Code(root);
Code(BTNode<
*t)//编码
ofstreamoutf("
textfile.txt"
);
if(!
outf)
cout<
Cannotopenthefile\n"
return;
ofstreamouts("
codefile.txt"
ios:
trunc);
outs)
outs.close();
charstr2[100];
请输入由字符集中字符组成的任意字符串:
str2;
outf<
outf.close();
intl=strlen(str2);
编码为:
<
l;
Make(root,str2[i]);
Make(BTNode<
*t,chara)
inti=0;
ch==a)//找到相应字符
ofstreamouts("
app);
cout<
outs<
//将编码写入文件
outs.close();
return;
Make(t->
lChild,a);
rChild,a);
Compile()//译码
Compile(root);
Compile(BTNode<
*t)
ifstreaminf("
inf)
result.txt"
char*re;
chartmp;
intn=0;
while(inf.get(tmp)!
='
\0'
)
n++;
//确定字符数量
inf.close();
re=newchar[n+1];
intn2=0;
ifstreamin("
in)
cout<
while(in.get(tmp)!
re[n2]=tmp;
//将字符读入一位数组
n2++;
*c;
译码为:
intn3=0;
while(n3<
n)
while(t)
c=t;
if(re[n3]=='
0'
)//左0右1根据0或1向左走向右走直到叶子结点
t=t->
else
rChild;
n3++;
ofstreamouts("
if(!
c->
ch;
//输出字符
outs<
//将结果写进文件
outs.close();
t=root;
n3--;
voidPrint()
charstr;
ifstreama("
ifstreamb("
ifstreamc("
a)
b)
c)
textfile.txt内的内容为:
while(a.get(str)!
codefile.txt内的内容为:
while(b.get(str)!
result.txt内的内容为:
while(c.get(str)!
a.close();
b.close();
c.close();
五、测试和调试
1)输入B选择建树操作
2)分别输入a,b,c,d以及权值2,4,1,1,建树
3)输入T得到该树的遍历
4)输入E生成编码
5)输入C编码,输入字符串aabdcbdacbdadcdb
6)输入D选择译码
7)输入P选择打印文件内容
8)最后输入X退出
2.结果分析
1)程序能够完全实现题目的要求,建树,遍历生成编码,编码以及译码打印都能成功完成
2)不足之处在于译码方面,不能够实现自己输入一串编码来实现译码,下一步的目标是解决这个问题
实习小结
通过这次课程设计,使我对二叉树的相关知识有了更深的理解,我们要根据不同的需求,采用不同的数据存储方式,不一定要用栈,二叉树等高级类型,有时用基本的一维数组,只要运用得当,也能达到相同的效果,甚至更好。
同样的,这次在在程序的运行与调试过程中也出现了很多错误,通过反复地阅读课本上的知识,并且又对哈夫曼树的构造以及哈夫曼编码译码有了更深的理解。
在完成实验的过程中,不停地修改与调试,在调试过程中,我也认识到了自己更多的不足以及在细节上的把握不够,如对队列的知识不够熟悉,在使用过程中出现了很多问题。
在以后的学习中我要集中精力、端正态度,争取把知识学得更扎实、更全面。
附录:
1.二叉树的基本操作
#include<
iostream>
string>
usingnamespacestd;
structBTNode//结点类
BTNode(){lChild=rChild=NULL;
BTNode(constT&
x)
element=x;
lChild=rChild=NULL;
x,BTNode<
*l,BTNode<
*r)
lChild=l;
rChild=r;
Telement;
*lChild,*rChild;
};
//循环队列类
classSeqQueue
public:
SeqQueue(intmSize);
~SeqQueue(){delete[]q;
boolIsEmpty()const{returnfront==rear;
boolIsFull()const{return(rear+1)%maxSize==front;
boolFront(BTNode<
*&
x)const;
boolEnQueue(BTNode<
*x);
boolDeQueue();
voidClear(){front=rear=0;
private:
intfront,rear;
intmaxSize;
**q;
SeqQueue<
SeqQueue(intmSize)//构造函数
maxSize=mSize;
q=newBTNode<
*[maxSize];
front=rear=0;
boolSeqQueue<
Front(BTNode<
x)const//取队头元素
if(IsEmpty())
returnfalse;
x=q[(front+1)%maxSize];
returntrue;
EnQueue(BTNode<
*x)//在队尾插入x
if(IsFull())
Full"
q[rear=(rear+1)%maxSize]=x;
DeQueue()//删除队头元素
Underflow"
front=(front+1)%maxSize;
//Visit函数
voidVisit(T&
x)
x<
//二叉树类
classBinaryTree
BinaryTree():
s(100){root=NULL;
~BinaryTree(){delete[]root;
boolClear();
voidMakeTree(constT&
x,BinaryTree<
left,BinaryTree<
right);
intHigh(BTNode<
*p);
intNode_num(BTNode<
*Copy(BTNode<
*t);
voidExchange(BTNode<
t);
voidLevel_traversal(void(*Visit)(T&
x));
*root;
protected:
SeqQueue<
s;
voidClear(BTNode<
*&
MakeTree(constT&
right)//建树
if(root||&
left==&
right)return;
root=newBTNode<
(x,left.root,right.root);
left.root=right.root=NULL;
boolBinaryTree<
Clear()//删除
Clear(root);
if(root==NULL)
returntrue;
Clear(BTNode<
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 上机 实验 二叉 基本 操作 哈夫曼 编码 译码 系统 实现