二叉树的遍历实验报告
一、需求分析
在二叉树的应用中,常常要求在树中查找具有某种特征的结点,或者对树中全部结点逐一进行某种处理,这就是二叉树的遍历问题。
对二叉树的数据结构进行定义,建立一棵二叉树,然后进行各种实验操作。
二叉树是一个非线性结构,遍历时要先明确遍历的规则,先访问根结点还时先访问子树,然后先访问左子树还是先访问有右子树,这些要事先定好,因为采用不同的遍历规则会产生不同的结果。本次实验要实现先序、中序、后序三种遍历。
基于二叉树的递归定义,以及遍历规则,本次实验也采用的是先序遍历的规则进行建树的以及用递归的方式进行二叉树的遍历。
二、系统总框图
三、各模块设计分析
(1)建立二叉树结构
建立二叉树时,要先明确是按哪一种遍历规则输入,该二叉树是按你所输入的遍历规则来建立的。本实验用的是先序遍历的规则进行建树。
二叉树用链表存储来实现,因此要先定义一个二叉树链表存储结构。因此要先定义一个结构体。此结构体的每个结点都是由数据域data、左指针域Lchild、右指针域Rchild组成,两个指针域分别指向该结点的左、右孩子,若某结点没有左孩子或者右孩子时,对应的指针域就为空。最后,还需要一个链表的头指针指向根结点。
要注意的是,第一步的时候一定要先定义一个结束标志符号,例如空格键、#等。当它遇到该标志时,就指向为空。
建立左右子树时,仍然是调用create()函数,依此递归进行下去,直到遇到结束标志时停止操作。
(2)输入二叉树元素
输入二叉树时,是按上面所确定的遍历规则输入的。最后,用一个返回值来表示所需要的结果。
(3)先序遍历二叉树
当二叉树为非空时,执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。
(4)中序遍历二叉树
当二叉树为非空时,程序执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。
(5)后序遍历二叉树
当二叉树为非空时,程序执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。
(6)主程序
需列出各个函数,然后进行函数调用。
四、各函数定义及说明
因为此二叉树是用链式存储结构存储的,所以定义一个结构体用以存储。
typedef struct BiTNode
{ char data;
struct BiTNode *Lchild;
struct BiTNode *Rchild;
}BiTNode,*BiTree;
(1)主函数main()
主程序要包括:定义的二叉树T、建树函数create()、先序遍历函数Preorder()、中序遍历函数Inorder()、后序遍历函数Postorder()。
(2)建树函数Create()
定义一个输入的数是字符型的,当ch为空时,T就为空值,否则的话就分配空间给T,T就指向它的结点,然后左指针域指向左孩子,右指针指向右孩子,若还有,继续调用Create(),依次循环下去,直到ch遇到空时,结束。
最后要返回建立的二叉树T。
(3)先序遍历函数Preorder()
根据先序遍历规则,当T为非空时,先输出结点处的数据,指针指向左、右孩子,依次进行下去。
(4) 中序遍历函数Inorder()
根据中序遍历规则,当T为非空时,先左指针指向左孩子数据,然后输出结点处的数据,再右指针指向右孩子,依次进行下去。
(5)后序遍历函数Postorder()
根据后序遍历规则,当T为非空时,先右指针指向右孩子,然后左指针指向左孩子,最后输出结点处的数据,依次进行下去。
五、使用说明
在Turbo C的环境下,先按Ctrl+F9运行程序,此时就是建立二叉树的过程,例如输入序列-+a *b -c d /e f 输入过程中不要加回车,因为回车也有对应的ASCII码,是要算字符的,输入完之后再按回车,用户界面上就能够看到结果了。
另外你必须会手动建立一棵二叉树,保证你输入的序列能构成一棵二叉树,否则你怎么输入,按最后按多少回车程序也不会结束!
六、源程序
#include "stdio.h"
#include "string.h"
#include "alloc.h"
#define NULL 0
typedef struct BiTNode
{
char data;
struct BiTNode *Lchild;
struct BiTNode *Rchild;
}BiTNode,*BiTree;
BiTree Create()
{
char ch;
BiTree T;
scanf("%c",&ch);
if(ch==' ')
T=NULL;
else
{ T=(BiTNode *)malloc(sizeof(BiTNode));
T->data=ch;
T->Lchild=Create();
T->Rchild=Create();
}
return T;
}
void Preorder(BiTree T)
{
if(T)
{
printf("%c",T->data);
Preorder(T->Lchild);
Preorder(T->Rchild);
}
}
void Inorder(BiTree T)
{
if(T)
{
Inorder(T->Lchild);
printf("%c",T->data);
Inorder(T->Rchild);
}
}
void Postorder(BiTree T)
{
if(T)
{
Postorder(T->Lchild);
Postorder(T->Rchild);
printf("%c",T->data);
}
}
main()
{
BiTree T;
clrscr();
printf("The elements is : ");
T=Create();
printf("\n");
printf("The Preorder's result is : ");
Preorder(T);
printf(" \n\n");
printf("The Inorder's result is : ");
Inorder(T);
printf("\n\n");
printf("The Postorder's result is : ");
Postorder(T);
getch();
}
七、测试数据
八、测试结果
先序遍历序列:-,+,a,*,b,-,c,d,/,e,f ;
中序遍历序列:a,+,b,*,c,-,d,-,e,/,f ;
后序遍历序列:a,b,c,d,-,*,+,e,f,/,- ;
线索化二叉树遍历实验报告
09040502班 学号:052415 朱博凯
一、 需求分析
(1) 本程序需要用户自行输入二叉树(二叉树的数据可以是任何字符),用”#”表示空格,按回车键结束!
(2) 程序功能:遍历二叉树,线索化二叉树,遍历线索化二叉树,二叉树去线索化。
(3) 测试数据:
ABC##DE#G##F###;
二、 概要设计
为实现本程序功能,应以二叉树结构存储二叉树,而为了实现非递归遍历二叉树的功能,应以带头节点的栈存储二叉树。
1、 二叉树的抽象数据类型定义
ADT BinaryTree{
数据对象D:D是具有相同特性的数据元素集合。
数据关系R:如D=Ф,则R=Ф,称BinaryTree为空二叉树;
如D≠Ф,则R={H},H是如下二元关系:
(1) 在D中存在唯一的称为根的数据元素root,它在关系H下无前驱;
(2) 如D-{root}≠Ф,则存在D-{root}={D1,Dr},且D1∩Dr=Ф;
(3) 如D1≠Ф,则D1中存在唯一元素x1,<ROOT,X< SPAN>1>∈H,且存在D1上的关系H1∈H;如Dr≠Ф,则Dr中存在唯一的元素xr,<ROOT,X< SPAN>r>∈H,且存在Dr上的关系Hr包含于H;H={<ROOT,X< SPAN>1>,<ROOT,X< SPAN>r>,H1,Hr};
(4) (D1,{H1})是一棵符合本定义的二叉树,称为根的右子树。
基本操作 P:
InitBiTree(&T);
操作结果:构造空二叉树T.
DestroyBiTree(&T);
初始条件:二叉树T存在。
操作结果:销毁二叉树T.
CreateBiThrTree(&T);
操作结果:先序构造二叉树T,Ltag和RTag初始置为Link.
PreOrderTraverse(T );
初始条件:二叉树T存在。
操作结果:先序递归遍历T。
InOrderTraverse(T);
初始条件:二叉树T存在。
操作结果:中序递归遍历T。
PostOrderTraverse(T);
初始条件:二叉树T存在。
操作结果:后序递归遍历T。
InOrderThreading(&ThrT, T);
初始条件:二叉树T存在。
操作结果:建立头结点ThrT,并调用InThreading(T);函数。
InThreading(T);
初始条件:二叉树T存在。
操作结果:中序线索化二叉树T;
InOrderTrasverse_Thr(T);
初始条件:二叉树T存在。
操作结果:中序扫描线索化的二叉树。
}ADT BinaryTree
2、 栈的抽象数据类型定义
ADT Stack{
数据对象:d={ ai |ai∈elemset,i=1,2,3,……,n,n≥0}
数据关系:r={<ai-1,ai,)>| ai-1,ai ∈d, i=2,3,……,n}
约定a1为栈底,an 为栈顶。
基本操作:
(1)InitStack(&S)
操作结果:构造一个空栈S。
(2)DestroyStack(&S)
初始条件:栈S已存在。
操作结果:销毁栈S。
(3)ClearStack(&S)
初始条件:栈S已存在。。
操作结果:将栈清空为空栈。
(4)StackEmpty(&S)
初始条件:栈S已存在。
操作结果:若栈S为空栈,则返回TRUE,否则FALSE。
(5)StackLength(&S)
初始条件:栈S已存在。
操作结果:返回栈的长度(或者说深度)。
(6)GetTop(S,&e)
初始条件:栈S已存在且非空。
操作结果:用e返回S的栈顶元素。
(7)Push(&S,e)
初始条件:栈S已存在。
操作结果:在栈顶插入新的元素e。
(8)Pop(&S,&e)
初始条件:栈S已存在且非空。
操作结果:删除栈S的栈顶元素,并且用e返回它的值。
(9)StackTraverse(S,visit())
初始条件:栈S已存在。
操作结果:遍历访问栈,一次对S的每个元素调用函
}ADTStack
3、 程序包括6个模块
1)主程序模块:
2)创建二叉树;
3)计算树的高度;
4)递归遍历二叉树(先、中、后序);
5)非递归遍历二叉树(先、中序);
6)线索化二叉树(先、中序);
7)二叉树去线索化;
三、 详细设计
1、 元素类型、结点类型
typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild ,*rchild;
PointerTag LTag , RTag;
}BiTNode , *BiTree , BiThrNode , *BiThrTree; //二叉树
typedef struct{
BiTree *base;
BiTree *top;
int stacksize;
}SqStack; //栈
2、 栈的实现
typedef struct{
char *base;
char *top;
int stacksize;
}SqStack; //栈类型
栈的基本操作设置如下:
void InitStack(Stack &S)
//初始化,设S为空栈(S.top=NULL)
void DestroyStack(Stack &S)
//销毁栈S,并释放所占空间
void ClearStack(Stack &S)
//将S清为空栈
int StackLength(Stack S)
//返回栈S的长度S.size
Status StackEmpty(Stack S)
//若S为空栈(S.top==NULL),则返回TRUE;否则返回FALSE
Status GetTop(Stack S,ElemType e)
//若栈S不空,则以e带回栈顶元素并返回TRUE,否则返回FALSE
Status Push(Stack&S,ElemType e)
//若分配空间成功,则在S的栈顶插入新的栈顶元素e,并返回TRUE,
//否则返回FALSE
void StackTraverse(Stack S,Status (*visit)(ElemType e))
//从栈底到栈顶依次对S中的每个结点调用函数visit
3、 主函数和其他函数的伪码
typedef int status;
typedef char TElemType;
typedef enum PointerTag{Link,Thread};
//二叉树的操作
status CreatBiTree(BiTree &T);
status treedepth(BiTree T);
status Visit(TElemType e);
status PreOrderTraverse(BiTree T,status(*Visit)(TElemType e));
status InOrderTraverse(BiTree T,status(*Visit)(TElemType e));
status PostOrderTraverse(BiTree T,status(*Visit)(TElemType e));
status UnInOrderTraverse(BiTree T,status(*Visit)(TElemType e));//非递归中序遍历
status UnPreOrderTraverse(BiTree T,status(*Visit)(TElemType e));//非递归先序遍历
//线索化二叉树的操作
void InOrderThreading(BiThrTree &Thrt,BiThrTree T);
void InThreading(BiThrTree p);
status InOrderTraverse_Thr(BiThrTree T, status (*Visit)(TElemType e));
void PreOrderThreading(BiThrTree &Thrt,BiThrTree T);
status PreOrderTraverse_Thr(BiThrTree T, status (*Visit)(TElemType e));
void PreThreading(BiThrTree p);
void UnThreading(BiThrTree &Thrt);
//栈的操作
status InitStack(SqStack &S);
status GetTop(SqStack S , BiTree &e);
status Push(SqStack &S , BiTree e);
status Pop(SqStack &S , BiTree &e);
status StackEmpty(SqStack S);
//全局变量
SqStack S;
BiThrTree pre;
BiThrTree i;
void main() //主函数
{
printf("\t************\n\t*二叉树演示*\n\t************\n");
BiTree T;
BiThrTree Thrt;
printf("\n创建二叉树(用#表示空格):\n");
CreatBiTree(T);
printf("树的高度为:%d",treedepth(T));
printf("\n递归先序遍历:");
PreOrderTraverse(T , Visit);
printf("\n递归中序遍历:");
InOrderTraverse(T , Visit);
printf("\n递归后序遍历:");
PostOrderTraverse(T , Visit);
printf("\n非递归中序遍历:");
UnInOrderTraverse(T , Visit);
printf("\n非递归先序遍历:");
UnPreOrderTraverse(T , Visit);
printf("\n中序遍历线索化二叉树:");
InOrderThreading(Thrt , T);
InOrderTraverse_Thr(Thrt , Visit);
printf("\n后序递归去线索化并输出:");
UnThreading(Thrt);
printf("\n先序遍历线索化二叉树:");
PreOrderThreading(Thrt , T);
printf("\n");
}
status CreatBiTree(BiTree &T)
//创建二叉树
{
char ch;
ch=getchar();
if(ch=='#')
T=NULL;
else{
if(!(T=(BiTNode *)malloc(sizeof(BiTNode))))
return ERROR;
T->data=ch;
if (CreatBiTree(T->lchild)) T->LTag=Link;
if (CreatBiTree(T->rchild)) T->RTag=Link;
}
return OK;
}
status treedepth(BiTree T)
//计算树的高度
{
int lchilddep,rchilddep;
if(T==NULL)
return 0;
else
{
lchilddep=treedepth(T->lchild);
rchilddep=treedepth(T->rchild);
if(lchilddep>rchilddep)
return lchilddep+1;
else
return rchilddep+1;
}
}
status Visit(TElemType e)
{
printf("%c",e);
return OK;
}
status PreOrderTraverse(BiTree T,status(*Visit)(TElemType e))
//递归先序遍历
{
if(T)
{
if(Visit(T->data))
if(PreOrderTraverse(T->lchild,Visit))
if(PreOrderTraverse(T->rchild,Visit))
return OK;
return ERROR;
}
else
return OK;
}//PreOrderTraverse
status InOrderTraverse(BiTree T,status(*Visit)(TElemType e))
//递归中序遍历
{
if(T)
{
if(InOrderTraverse(T->lchild,Visit))
if(Visit(T->data))
if(InOrderTraverse(T->rchild,Visit))
return OK;
return ERROR;
}
else return OK;
}//InOrderTraverse
status PostOrderTraverse(BiTree T,status(*Visit)(TElemType e))
//递归后序遍历
{
if(T)
{
if(PostOrderTraverse(T->lchild,Visit))
if(PostOrderTraverse(T->rchild,Visit))
if(Visit(T->data))
return OK;
return ERROR;
}
else return OK;
}//PostOrderTraverse
status UnInOrderTraverse(BiTree T,status(*Visit)(TElemType e))
//非递归中序遍历
{
BiTree p;
InitStack(S);
Push(S,T);
while(!StackEmpty(S))
{
while(GetTop(S,p) && p)
Push(S,p->lchild);
Pop(S,p);
if(!StackEmpty(S))
{
Pop(S,p);
if(!Visit(p->data))
return ERROR;
Push(S,p->rchild);
}//if
}//while
return OK;
}//UnInOrderTraverse
status UnPreOrderTraverse(BiTree T,status(*Visit)(TElemType e))
//非递归先序遍历
{
BiTree p;
InitStack(S);
p=T;
while(p||!StackEmpty(S))
{
if(p)
{
if(!Visit(p->data))
return ERROR;
Push(S,p);
p=p->lchild;
}
else
{
Pop(S,p);
p=p->rchild;
}//else
}//while
return OK;
}//UnPreOrderTraverse
void InOrderThreading(BiThrTree &Thrt,BiThrTree T)
//中序遍厉二叉树T,并将其中序线索化,Thrt指向头结点
{
if(!(Thrt=(BiThrTree)malloc(sizeof(BiThrNode)))) exit(OVERFLOW);
Thrt->LTag=Link;//建头结点
Thrt->RTag=Thread;
Thrt->rchild=Thrt;//右指针回指
if(!T)
Thrt->lchild=Thrt;
else
{
Thrt->lchild=T;
pre=Thrt;
InThreading(T);//中序遍历进行中序线索化
pre->rchild=Thrt;
pre->RTag=Thread;//最后一个结点线索化
Thrt->rchild=pre;
}
i=Thrt;
}//InOrderThreading
void InThreading(BiThrTree p) //线索化
{
if(p)
{
InThreading(p->lchild);
if(!p->lchild)
{
p->LTag = Thread;
p->lchild = pre;
}
if(!pre->rchild)
{
pre->RTag = Thread;
pre->rchild = p;
}
pre = p;
InThreading(p->rchild);
}
}//InThreading
void UnThreading(BiThrTree &Thrt) //后序去线索化
{
BiThrTree p=Thrt;
if(p)
{
if(p->LTag == Thread)
{
p->lchild = NULL;
p->LTag = Link;
}
if(p->LTag == Link && p->lchild) UnThreading(p->lchild);
if(p->RTag == Link && p->rchild)UnThreading(p->rchild);
if(p != i) Visit(p->data);
}
}
status InOrderTraverse_Thr(BiThrTree T, status (*Visit)(TElemType e))
//中序遍历线索化后的二叉树
{
BiThrTree p;
p=T->lchild;
while(p!=T)
{
while(p->LTag==Link)
p=p->lchild;
if(!Visit(p->data))
return ERROR;
while(p->RTag==Thread && p->rchild!=T)
{
p=p->rchild;
Visit(p->data);
}
p=p->rchild;
}
return OK;
}
void PreOrderThreading(BiThrTree &Thrt,BiThrTree T)
//先序遍厉二叉树T,并将其先序线索化,Thrt指向头结点
{
if(!(Thrt=(BiThrTree)malloc(sizeof(BiThrNode)))) exit(OVERFLOW);
Thrt->LTag=Link;
Thrt->RTag=Thread;//建头结点
Thrt->rchild=Thrt;//右指针回指
if(!T)
Thrt->lchild=Thrt;
else
{
Thrt->lchild=T;
pre=Thrt;
PreThreading(T);//先序遍历进行先序线索化
pre->rchild=Thrt;pre->RTag=Thread;//最后一个结点线索化
Thrt->rchild=pre;
}
i=Thrt;
}
status PreOrderTraverse_Thr(BiThrTree T, status (*Visit)(TElemType e))
//先序遍历线索化后的二叉树
{
BiThrTree p;
p=T->lchild;
while(p!=T)
{
while(p->LTag==Link)
p=p->lchild;
if(!Visit(p->data))
return ERROR;
while(p->RTag==Thread && p->rchild!=T)
{
p=p->rchild; Visit(p->data);
}
p=p->rchild;
}
return OK;
}//PreOrderTraverse_Thr
void PreThreading(BiThrTree p) //先序线索化
{
if(p)
{
if(!p->lchild)
{
p->LTag = Thread;
p->lchild = pre;
}
if(!pre->rchild)
{
pre->RTag = Thread;
pre->rchild = p;
}
pre = p;
Visit(p->data);
if(p->LTag==Link)
PreThreading(p->lchild);
if(p->RTag == Link)
PreThreading(p->rchild);
}
}//PreThreading
status InitStack(SqStack &S) //栈的初始化
{
S.base=(BiTree *)malloc(STACK_INIT_SIZE * sizeof(BiTree));
if(!S.base)exit(OVERFLOW);
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
status GetTop(SqStack S , BiTree &e) //取顶元素
{
if(S.top == S.base) return ERROR;
else{
e = *(S.top-1);
return OK;
}
}
status Push(SqStack &S , BiTree e) //进栈
{
if(S.top - S.base >= S.stacksize)
{
S.base = (BiTree *)realloc(S.base , (S.stacksize + STACKINCREMENT) * sizeof(BiTree));
if(!S.base) exit(OVERFLOW);
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e;
return OK;
}
status Pop(SqStack &S , BiTree &e) //出栈
{
if(S.top == S.base)
return ERROR;
else{
e = * --S.top;
return OK;
}
}
status StackEmpty(SqStack S) //检查栈是否为空
{
if(S.top == S.base)
return 1;
else
return 0;
}
4、 函数间调用关系
四、 调试分析
1. 在线索化二叉树时,如果像书上把二叉树和线索二叉树的存储结构分开,则二叉树中的数据域不能传递到线索二叉树中(两个类型的指针不能互相赋值)。比较两种存储结构发现,线索二叉树比二叉树多了两个标志域LTag,Rtag。于是把两种存储结构合并为BiThrNode,并在建立二叉树时把LTag,Rtag均置为Link。程序正常运行。
2. 本次实验报告所用的算法,书中均有具体算法演示,且易实现,除存储结构外没有大问题。
五、 用户手册
1. 本程序开发环境为VC 6.0,运行环境为dos操作系统,执行文件为:Binary Tree.exe
2. 运行该程序的Binary Tree.exe文件,产生如下图所示的界面
3. 按照提示输入二叉树(以”#”表示空格)。
4. 输入完成后,按回车键。
5. 屏幕上打印出对应于该二叉树的的各种遍历结果。
六、 测试结果
输入一个二叉树: abc##de#g##f###
屏幕打印结果:
树的高度为: 5
递归先序遍历: abcdegf
递归中序遍历: cbegdfa
递归后序遍历: cgefdba
非递归中序遍历: cbegdfa
非递归先序遍历: abcdegf
中序遍历线索化二叉树: cbegdfa
后序递归去线索化并输出: cgefdba
先序遍历线索化二叉树: abcdegf
七、 附录
源程序文件名清单:
Binary Tree.cpp //主程序
Binary Tree.exe //可执行文件
stdio.h //程序中用到的头文件
stdlib.h
实验四二叉树的操作班级:计算机1002班姓名:**学号:**完成日期:20XX.6.14题目:对于给定的一二叉树,实现各种约定的遍…
实验六树和二叉树的操作一实验目的1进一步掌握树的结构及非线性特点递归特点和动态性2进一步巩固对指针的使用和二叉树的三种遍历方法建立…
树和二叉树一实验目的1掌握二叉树的结构特征以及各种存储结构的特点及适用范围2掌握用指针类型描述访问和处理二叉树的运算二实验要求1认…
宁波工程学院电信学院计算机教研室实验报告一实验目的1熟悉二叉树树的基本操作2掌握二叉树的实现以及实际应用3加深二叉树的理解逐步培养…
二叉树实验报告问题描述1问题描述用先序递归过程建立二叉树存储结构二叉链表输入数据按先序遍历所得序列输入当某结点左子树或右子树为空时…
实验三二叉树的建立及遍历实验目的1掌握利用先序序列建立二叉树的二叉链表的过程2掌握二叉树的先序中序和后序遍历算法实验内容1编写程序…
实验12二叉树遍历题目实现链式存储的二叉树的多种遍历算法包括递归非递归以及线索二叉树等班级信息学院20xx级理科实验班1班姓名学号…
数据结构实验报告计科101冯康20xx00814128实验五图的基本操作一实验目的1使学生可以巩固所学的有关图的基本知识2熟练掌握…
数据结构验报告实验图的遍历一实验目的1理解并掌握图的逻辑结构和物理结构邻接矩阵邻接表2掌握图的构造方法3掌握图的邻接矩阵邻接表存储…
电子信息工程学系实验报告适用于计算机课程课程名称数据结构实验项目名称图的遍历操作实验时间班级计应102姓名学号实验目的掌握有向图和…
算法与数据结构实验报告——二叉树课程名称:算法与数据结构实验项目名称:满二叉树的建立与遍历实验时间:20xx年x月x日班级:电科1…