最新数据结构实验报告x
时间:2020-11-22 12:46:18 来源:勤学考试网 本文已影响 人
实验目的
( 1 )学会用先序创建一棵二叉树。
( 2 )学会采用递归算法对二叉树进行先序、中序、后序遍历。
( 3 )学会打印输出二叉树的遍历结果。
实验内容
【问题描述】建立一棵二叉树,并对其进行遍历(先序、中序、后序) , 打印输出遍历结果。
【基本要求】
从键盘接受输入(先序) ,以二叉链表作为存储结构,建立二叉树(以先 序来建立),并采用递归算法对其进行遍历(先序、中序、后序) ,将遍历 结果打印输出。
【测试数据】
ABC DE ?G 其中?表示空格字符)
则输出结果为 先序: ABCDEGF
中序: CBEGDFA
后序: CGBFDBA
【选作内容】
采用非递归算法实现二叉树遍历。
实验步骤
(一)需求分析
、在这个过程中, 接受遍历的二叉树是从键盘接受输入 (先序), 以二叉链表作为存储结构,建立的二叉树。因此,首先要创建一 棵二叉树,而这棵二叉树是先序二叉树。本演示程序中,集合的 元素设定为大写字母 ABCDEFG ,输出的先序, 中序, 后序遍历 分别为 ABCDEGF,CBEGDFA,CGBFDBA 。二叉树可以表示 为:
A
接受的输入数据在进行递归的先序,中序,后序遍历后,分别将
结果打印出来。
2、 在程序运行的过程中可以看到,以计算机提示用户执行的方 式进行下去,即在计算机终端上提示“输入二叉树的先序序列”
后,由用户在键盘上输入 ABC##DE#G##F### ,之后相应的选 择遍历及遍历结果显示出来。
3、 程序执行的命令包括:首先是二叉树的先序序列被创建输入, 其次是对输入进去的先序序列有次序的进行先序,中序,后序遍 历。最后是打印出二叉树的遍历结果
T=(BTNode *)malloc(sizeof(BTNode));
T=(BTNode *)malloc(sizeof(BTNode)); // 分配空间,生成
4 、测试数据
)在键盘上输入的先序序列 ABC##DE#G##F###
)先序遍历结果 ABCDEGF
)中序遍历结果 CBEGDFA
)后序遍历结果 CGBFDBA
二)概要设计
1、为实现上述程序功能,应以二叉树定义的相关操作和二
叉树递归遍历的相关操作为依据 构,建立二叉树的操作为: typedef BTNode *BTree;BTree CreatBTree(void){BTree T;
叉树递归遍历的相关操作为依据 构,建立二叉树的操作为: typedef BTNode *BTree;
BTree CreatBTree(void)
{
BTree T;
char ch;
if((ch=getchar())=='#')
return(NULL);
else{
有关以二叉链表作为存储结
// 定义二叉树的指针
// 读入 #,返回空指针
结点
T->data=ch;
T->lchild=CreatBTree(); // 构造左子树
T->rchild=CreatBTree(); // 构造右子树 return(T);
}
}
、而有关先序、中序、后序遍历的递归操作为:
void Preorder(BTree T)
{
if(T){
printf("%c",T->data);
Preorder(T->lchild);
Preorder(T->rchild);
}
// 先序遍历
// 先序遍历
// 访问结点
// 先序遍历左子树
// 先序遍历右子树
void Inorder(BTree T)
// 中序遍历
}
}
if(T)
{
Inorder(T->lchild);
printf("%c",T->data);
Inorder(T->rchild);
}
}
// 中序遍历左子树
// 访问结点
// 中序遍历右字树
void Postorder(BTree T)
{
if(T)
{
Postorder(T->lchild);
Postorder(T->rchild);
printf("%c",T->data);
// 后序遍历
// 后序遍历左子树
// 后序遍历右子树
// 访问结点
3、本程序包含的模块
结点单元模块
构建先序二叉树模块
(3 )二叉树遍历模块
(4)主程序模块
各模块之间的调用关系如下:
主程序模块
结点单元模块
构建先序二叉树模块
二叉树遍历模块
(三)详细设计
1、元素类型,结点类型和指针类型 typedef struct node
char data;// 二叉树的元素类型
char data;
struct node *lchild;
struct node *rchild;
// 自定义二叉树的结类型
// 自定义二叉树的结类型
// 定义二叉树的指针
typedef BTNode *BTree;
2 、定义类型之后, 要以二叉链表作为存储结构, 建立二叉树(以 先序来建立)。
BTree CreatBTree(void){
BTree CreatBTree(void)
{
BTree T;
char ch;
if((ch=getchar())=='#')
叉树
return(NULL);
// 定义输入的数据类型
// 支持在键盘上输入先序二
// 读入 # ,返回空指针
对于二叉树的先序输入,在输入中要注意的是对于空指针的
把握,由于是先序输入,在输入时要在确定的位置输入“ # ”号, 否则先序二叉树将不完整。
else{
T=(BTNode *)malloc(sizeof(BTNode)); // 分配空间,生
成结点
T->data=ch;
T->lchild=CreatBTree(); // 构造左子树
T->rchild=CreatBTree(); // 构造右子树
return(T);
}
}
当输入的叶子结点完整之后,要 return(T) ,否则输入将一直持 续下去不能跳出来。在程序的设计过程中,在适当的位置插入 # 对于二叉树的遍历有着十分重要的作用,因此要明白二叉树的先 序创建过程如何运行。
、对于二叉树进行先序、中序、后序的遍历
void Preorder(BTree T)//
void Preorder(BTree T)
// 先序遍历
}
}
{
{
if(T){
// 访问结点
// 访问结点
// 先序遍历左子树
// 先序遍历右子树
Preorder(T->lchild);
Preorder(T->rchild);
}
// 中序遍历
// 中序遍历
void Inorder(BTree T)
if(T)
Inorder(T->lchild);
// 中序遍历左子树
printf("%c",T->data);
// 访问结点
Inorder(T->rchild);
// 中序遍历右字树
}
}
void Postorder(BTree T)
{
if(T)
{
Postorder(T->lchild);
Postorder(T->rchild);
// 后序遍历//
// 后序遍历
// 后序遍历左子树
// 后序遍历右子树
// 访问结点
4、主程序模块的链接。在这个模块中,不仅要实现二叉树先序
序列从键盘的输入,还要实现选择三个遍历的输出。主函数的作
用旨在使每个程序模块能够链接在一起,调用各个函数以实现最 终的目的。
void main()
{
// 数的根结点
// 数的根结点
// 可供选择的整型变量 i
int i;
printf("\n");
printf(" 请输入二叉树的先序序列,用 # 代表虚结点 :");
root=CreatBTree();do{
root=CreatBTree();
do{
// 返回根结点
// 循环语句
printf("********************SELECT********************\n");
printf("\t1: 先序遍历 \n");
printf("\t2: 中序遍历 \n");
printf("\t3: 后序遍历 \n");
printf("\t0:Exit\n");
printf("\t*********************************************\n")
printf("\t*
******************************************
**\n")
scanf("%d",&i);// 输入菜单序号
switch(i)
{
case 1:printf(" 先序遍历结果为 :");
Preorder(root);
break;
case 2:printf(" 中序遍历结果为 :");
Inorder(root);
break;
case 3:printf(" 后序遍历结果为 :");
Postorder(root);
break;
在这三个选择中,充分调用了先序、中序、后序遍历函数,选
择 1 、2 、3 数字实现对三个遍历的输出打印。
default:exit(1);
}
prin tf("\n");
}
while(i!=O);
}
5、函数的调用关系图反映了演示程序的层次结构:
调试分析
1、实验涉及的部分包括用二叉链表创建先序二叉树,对二叉树 进行三种遍历,最后是对三种遍历结果进行打印。在做这个实验 的过程中,我们首先最先碰到的问题是用二叉链表存储先序二叉 树,由于对二叉树存储的不深入了解,我们在输入数据时,只能 对其无限输入,并不能及时的终止,导致的结果是程序停止不了, 运行不下去。不能返回的问题困扰了我们很久,在这个过程中,
我们还尝试了一些用栈来对其进行存储,通过一遍遍的摸索,最
终找到了正确的方法。在这个过程中,我们也对二叉树的存储有 了更为深刻的了解,相信这在我们以后的学习中也有很大的帮 助。
2 、在实验过程中,我们还有尝试了非递归的算法对于二叉树的 遍历,递归算法和非递归算法各有千秋,产用递归算法更为简单 明了。
3、根节点的运用没有得到合理的开发,在主程序的链接中,创 建二叉树,返回根节点。接着是一个 do 循环对于选择三种遍历 结果的打印输出和退出操作,在开始的程序设计阶段没有发挥作 用,前期使用的是 while 和 swith 语句,没有返回根结点,造成 算法的运行不能有序进行下去。
4、刚开始是忽略了一些细节问题,对于元素类型,结点类型的
定义没有认真检查,程序前期运行过程中有很多的失误,导致了 效率低下。今后一定要重视确定参数的变量和赋值属性的区别和 标志。
5、程序的设计基本是由一个个子模块联系到一起,由于前期没 有将这个程序的大致模型框架构架好,子模块之间的联系在主程 序中就出现了一些问题,因此在以后的实验过程中,要首先构造 大框架更有利于子模块的链接。
(五)用户手册
1、 本程序的运行环境为 DOS操作系统,本程序执行文件为“执 行二叉树建立与遍历.exe ”。
2、 进入程序运行后会有说明指示
首先创建二叉树按照完全二叉树的先序序列输入,以回车键结
束,程序主界面就会形成:
创建二戈林這输入克全二更材的先呼住列.
ELECT
31$ JfJfT
U:Exlt
3、按照要求输入各个功能的命令,程序接受命令后立即执行并
且显示相应的结果
(六)测试结果
(1)首先二叉链表存储(以先序创建)键盘输入
册二叉林薛入融二财漑序序乳用■代巔给点:《BC删河IFm 尊* 耳耳m* ■ NlnM FLICT ■■ 3<N*NNIlM M4MH
1;磧朗
—It
(2)选择数字“ 1 ”,先序遍历:
先辛湎万给垄为堆aci)謂f怕
先辛湎万给垄为堆aci)謂f
怕■?■■*■■■■ £ ELECT**
2氓壬遍瓦 J诟序遍圧
削建二艮护?睛输入宪兰二見桝前先序序列,用#弋希鏗吉点汕DCMDH*血阳删15历历
谊鲁U 先牡 ■?■_■■■■ 二 12
削建二艮护?睛输入宪兰二見桝前先序序列,
用#弋希鏗吉点汕DCMDH*血阳删
15历历
谊鲁
U 先牡 ■?■_■■■■ 二 12 3 0-
閱芹遽历结杲为
3;lff
OsExit
sflflCDEGF ******^ ELECT*1
调历
历
(3)选择数字“ 2 ”,中序遍历:
中序遍历结果为:仙EGJFR
鋼:hie,荼at w兰w lew就慕桂ac沌直掘吕ELEGT特制熹恤甘* M: *过廉齋sfirac科抗握■養:m [诜後页
2沖声毓
3踰遍历
8: Exit
请iS入死皇二罠村的先序评列.「则皆表虚笫黒“BCI^DRCM解?沖 MM M HHjCMMlifH 4 H.M H H |iiNMN.rig ELECTUMH 4 M 耳经暮植?融耳i诜应遍万
请iS入死皇二罠村的先序评列.「则皆表虚笫黒“BCI^DRCM解?沖 MM M HHjCMMlifH 4 H.M H H |iiNMN.rig ELECTUMH 4 M 耳经暮植?融耳
i诜应遍万
2;
3;后 SSffl
0:EkH
苧運冇鰭圭加CBEGDM
I鼻?鼻n耳■£ ELECT耳算翼”耳塁秆*鼻耳■■鼻
i吨圧朗 话焦门 欧血i*
K M mtSi M'M'rtlH H li MWffcC M M M 9t Si H*M^4*MH M H1 W! W 9f'BrMtl
予遍方结羌为:加血囲
■M WK, Ml Wilf, 3C1[豪■英第酬耳 KJf£ ELECT :MHi3flCM;iEiC]t iOflCMEWE>f]fM:^l[if? i=feffiiffi 2;匚声遍历 3:启声谯历
a:Exit
先序遍历结果为;ABCDEGF
■■轉■?! MHMWJtKW M Mg EL ECT
B:Exit中序H
B:Exit
中序H历结杲为:CBEGDFR 料 icy 钿 料 g 胚 L ECT
2:中庄遍厉
旅后库遍历
0:Exit
后序逋历结思为:
后序逋历结思为
:CGEFDBA 十十select
■iHttit
■iHttit :5tJ^E:EX 12 3 0
(七) 心得体会
此次的实验过程中,和以前的课程设计有一些不同之处,首次产 用团队合作的方式完成实验,我们也在这个过程中体会到了团队 合作的好处,大家积极分享彼此的经验,在分工的基础上合作, 在合作的前提下创新。学到了很多课本上没有的知识,也在团队 合作过程中提升了自身的能力。
(八) 附录:源程序清单
#in clude<stdio.h> #in clude<stdlib.h>
#include<string.h> //*****************************************************
typedef struct node
{
char data; // 二叉树的元素类型
struct node *lchild;
struct node *rchild;
}BTNode; // 自定义二叉树的结点类 型
typedef BTNode *BTree;BTree CreatBTree(void){
typedef BTNode *BTree;
BTree CreatBTree(void)
{
BTree T;
char ch;
if((ch=getchar())=='#')
先序二叉树
// 定义二叉树的指针
// 支持在键盘上输入
return(NULL);//
return(NULL);
// 读入 #,返回空指针
}
}
//
// 先序遍历
// 访问结点
// 先序遍历左子树
// 先序遍历右子树
else{
T=(BTNode *)malloc(sizeof(BTNode)); // 分配空间,生成 结点
T->data=ch;
T->lchild=CreatBTree(); // 构造左子树
T->rchild=CreatBTree(); // 构造右子树 return(T);
}
}
void Preorder(BTree T)
{
if(T){
printf("%c",T->data);
Preorder(T->lchild);
Preorder(T->rchild);
}
}
// 中序遍历//
// 中序遍历
// 中序遍历左子树
// 访问结点
// 中序遍历右字树
**************************************************** void Inorder(BTree T)
{
if(T)
{
Inorder(T->lchild);
printf("%c",T->data);
Inorder(T->rchild);
}
}
// 后序遍历
// 后序遍历
// 后序遍历左子树
// 后序遍历右子树
// 访问结点
void Postorder(BTree T)
{
if(T)
{
Postorder(T->lchild);
Postorder(T->rchild);
printf("%c",T->data);
}
void main()
{
BTree root; // 二叉树的根结点
int i;
printf("\n");
printf(" 请输入二叉树的先序序列,用 # 代表虚结点 :"); root=CreatBTree(); // 返回根结点 do{ //do 做循环打印遍历结果
n");
printf("\t1:
先序遍历 \n");
printf("\t2:
中序遍历 \n");
printf("\t3:
后序遍历 \n");
printf("\t0:Exit\n");
}
}
printf("\t*********************************************\n")
printf("\t*
******************************************
**\n")
scanf("%d",&i);// 输入菜单序号
switch(i)
{
case 1:printf(" 先序遍历结果为 :");
Preorder(root);
break;
case 2:printf(" 中序遍历结果为 :");
Inorder(root);
break;
case 3:printf(" 后序遍历结果为 :");
Postorder(root);
break;
default:exit(1);
printf("\n");
}
while(i!=0);
}
实验结果分析
在这个实验过程中,我们碰到了一些问题,比如说二叉树的存储 没有能够准确返回,主函数与模块函数之间没有实现很好的连接 造成调试程序上用了很多时间。忽略了一些细节问题,对于元素 类型,结点类型的定义没有认真检查,程序前期运行过程中有很 多的失误,导致了效率低下。但是我们充分发挥了团队的力量, 依次解决了这些问题,实验结果的正确性也得到了验证。虽说可 能仍存在一些不足之处,我们也会虚心接受,在过程中力求做到 尽可能的完善