1、数据结构实验报告题目:二叉树抽象数据类型学 院 计算机学院 专 业 计算机科学与技术 年级班别 学 号 学生姓名 指导教师 成 绩 _2013 年 6 月一实验概要实验项目名称: 二叉树抽象数据类型的实现实验项目性质: 设计性实验所属课程名称: 数据结构实验计划学时: 6二.实验目的1. 了解二叉树的定义以及各项基本操作。2. 实现二叉树存储、遍历及其他基本功能三. 实验仪器设备和材料硬件:PC 机 软件:Visual C+ 6.0四实验的内容1.二叉树类型定义以及各基本操作的简要描述;ADT BinaryTree 数据对象 D:D 是具有相同特性的数据元素的集合.数据关系 R:若 D=,则
2、R=,称 BinaryTree 为空二叉树;若 D,则 R=H,H 是如下二元关系:(1) 在 D 中存在惟一的称为根的数据元素 root,它在关系 H 下无前驱;(2) 若 D-root,则存在 D-root=D1,Dr,且D1Dr=;(3) 若 D1,则 D1 中存在惟一的元素 x1, H ,且存在 Dr 上的关系HrH;H= , ,H1,Hr;(4) (D1,H1)是一棵符合本定义的二叉树,称为根的左子树,是一棵符合本定义的二叉树,称为根的右子树。基本操作 P:InitBiTree(操作结果:构造空二叉树 T。DestroyBiTree(初始条件:二叉树 T 存在。操作结果:销毁二叉树
3、T。CreateBiTree(初始条件:definition 给出二叉树 T 的定义。操作结果:按 definition 构造二叉树 T。ClearBiTree(初始条件:二叉树 T 存在。操作结果:将二叉树 T 清为空树。BiTreeEmpty(T);初始条件:二叉树 T 存在。操作结果:若 T 为空二叉树,则返回 TURE,否则 FALSE。BiTreeDepth(T);初始条件:二叉树 T 存在。操作结果:返回 T 的深度。Root(T);初始条件:二叉树 T 存在。操作结果:返回 T 的根。Value(T,e);初始条件:二叉树 T 存在, e 是 T 中的某个结点。操作结果:返回 e
4、 的值。Assign(T,初始条件:二叉树 T 存在,e 是 T 中的某个结点。操作结果:结点 e 赋值为 value。Parent(T,e);初始条件:二叉树 T 存在,e 是 T 中的某个结点。操作结果:若 e 是 T 的非跟结点,则返回它的双亲,否则返回“空” 。LeftChild(T,e);初始条件:二叉树 T 存在, e 是 T 中的某个结点。操作结果:返回 e 的左孩子。若 e 无左孩子,则返回 “空” 。RightChild(T,e);初始条件:二叉树 T 存在, e 是 T 中的某个结点。操作结果:返回 e 的右孩子。若 e 无右孩子,则返回 “空” 。LeftSibling(
5、T,e);初始条件:二叉树 T 存在, e 是 T 中的某个结点。操作结果:返回 e 的左兄弟。若 e 无左孩子或无左兄弟,则返回 “空” 。RightSibling(T,e); 初始条件:二叉树 T 存在, e 是 T 中的某个结点。操作结果:返回 e 的右兄弟。若 e 无右孩子或无右兄弟,则返回 “空” 。ADT BinaryTree2.存储结构:采用无头结点的链式存储结构实现3.源代码:头文件及存储结构:#include#include#define TURE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW 0#de
6、fine MAXQSIZE 100 /最大队列长度typedef char TElemType; typedef struct BiTNode /二叉树结构体TElemType data;struct BiTNode *lchild,*rchild;BiTNode,*BiTree;typedef BiTree QElemType;typedef struct QNode QElemType data; struct QNode *next; QNode, *QueuePtr; /结点结构体typedef struct QueuePtr front; QueuePtr rear; LinkQue
7、ue; /链队列结构体 算法设计:int InitQueue(LinkQueue if(!Q.front) /存储分配失败 exit(OVERFLOW); Q.front-next = NULL;return OK; int EnQueue(LinkQueue p = (QueuePtr)malloc(sizeof(QNode); if(!p) /存储分配失败 exit (OVERFLOW); p-data = e; p-next = NULL; Q.rear-next = p; Q.rear = p; return OK; int DeQueue(LinkQueue if(Q.front =
8、 Q.rear) /队列为空队 return ERROR; p = Q.front-next; e = p-data; Q.front-next = p-next; if(Q.rear = p) /判断删除队头元素后,队列是否为空队 Q.rear = Q.front; free(p); return OK; int QueueEmpty(LinkQueue Q) /判断队列是否为空队 if (Q.front = Q.rear)return TURE;elsereturn FALSE;int InitBiTree(BiTree return OK;int DestroyTree(BiTree e
9、lseDestroyTree(T-lchild);DestroyTree(T-rchild);free(T);T=NULL;return OK;void CreateBiTree(BiTree scanf(“%c“,if(ch=)T=NULL;elseif(!(T=(BiTree)malloc(sizeof(BiTNode)exit(OVERFLOW); /分配存储空间失败T-data=ch;CreateBiTree(T-lchild); /构造左子树CreateBiTree(T-rchild); /构造右子树int ClearBiTree(BiTree elseClearBiTree(T-l
10、child);ClearBiTree(T-rchild);free(T);T=NULL;return OK;int BiTreeEmpty(BiTree T) /判断二叉树是否为空if(!T)return TURE;elsereturn FALSE;int BiTreeDepth(BiTree T) /计算二叉树深度int lcd,rcd;if(!T)return 0;lcd=BiTreeDepth(T-lchild);rcd=BiTreeDepth(T-rchild);return (lcdrcd?lcd:rcd)+1);TElemType Root(BiTree T) /判断二叉树是否空,
11、若非空返回其根if(BiTreeEmpty(T)return NULL;elsereturn (T-data);TElemType Value(BiTree T,BiTree e) /返回 e 结点的值return e-data;int Assign(BiTree T,BiTree return OK;TElemType Parent(BiTree T,TElemType e)/返回双亲LinkQueue q;QElemType a;if(T)InitQueue(q);EnQueue(q,T);/树根入队列while(!QueueEmpty(q)/队不空DeQueue (q, a);/出队,队
12、列元素赋给 aif(a-lchild /返回双亲的值elseif(a-lchild)EnQueue(q,a-lchild);/入队列左孩子if(a-rchild)EnQueue(q,a-rchild);/入队列右孩子return NULL;BiTree Point(BiTree T,TElemType s)/返回二叉树 T 中指向元素值为 S 的结点指针LinkQueue q;QElemType a;if(T)InitQueue(q);EnQueue(q,T);while(!QueueEmpty(q)DeQueue(q,a);if(a-data=s)return a;if(a-lchild)E
13、nQueue(q,a-lchild);if(a-rchild)EnQueue(q,a-rchild);return NULL;TElemType LeftChild(BiTree T,TElemType e)/返回 e 的左孩子BiTree a;if(T)a=Point(T,e);/a 是指向结点 e 的指针if(areturn NULL;TElemType RightChild(BiTree T,TElemType e) /返回 e 的右孩子BiTree a;if(T)if(a=Point(T,e)return NULL;TElemType LeftSibling(BiTree T,TEle
14、mType e) /返回左兄弟TElemType a;BiTree p;if(T)a=Parent(T,e);/a 为 e 的双亲if(a!=NULL)p=Point(T,a);/p 指向结点 a 的指针if(p-lchildreturn NULL;TElemType RightSibling(BiTree T,TElemType e) /返回右兄弟TElemType a;BiTree p;if(T)a=Parent(T,e);/a 为 e 的双亲if(a!=NULL)p=Point(T,a);/p 指向结点 a 的指针if(p-lchildreturn NULL;int InsertChil
15、d(BiTree T,BiTree p,int LR,BiTree c) /根据LR 为 0 或者 1,插入 C 为 T 中 P 所指结点的左或者右子树,/P 所指的结点原有左或右子树则成为 C 的右子树if(p)if(LR=0) /把二叉树 C 插入 p 所指结点的左子树c-rchild=p-lchild;p-lchild=c;elsec-rchild=p-rchild;p-rchild=c;return OK;return ERROR;int DeleteChild(BiTree T,BiTree p,int LR)if(p)if(LR=0)ClearBiTree(p-lchild);el
16、seClearBiTree(p-rchild);return OK;return ERROR;void visit(TElemType e) /二叉树结点访问函数printf(“%c“,e);int PreOrderTraverse(BiTree T,void(*visit)(TElemType) /先序遍历二叉树if(T)visit(T-data);PreOrderTraverse(T-lchild,visit);PreOrderTraverse(T-rchild,visit);return OK;return ERROR;int InOrderTraverse(BiTree T,void(
17、*visit)(TElemType) /中序遍历二叉树if(T)InOrderTraverse(T-lchild,visit);visit(T-data);InOrderTraverse(T-rchild,visit);return OK;return ERROR;int PostOrderTraverse(BiTree T,void(*visit)(TElemType) /后序遍历二叉树if(T) PostOrderTraverse(T-lchild,visit);PostOrderTraverse(T-rchild,visit);visit(T-data);return OK;return
18、 ERROR;int LevelOrderTraverse(BiTree T,void(*visit)(TElemType)/层序遍历二叉树LinkQueue q;QElemType a;if(T)InitQueue(q);/初始化队列EnQueue(q,T);/根指针入队while(!QueueEmpty(q)DeQueue(q,a);/出队元素,赋给 avisit(a-data);/访问 a 所指结点if(a-lchild!=NULL)EnQueue(q,a-lchild);if(a-rchild!=NULL)EnQueue(q,a-rchild);return OK;return ERR
19、OR;主函数:int main()int i,j,LR;TElemType value,a,temp;BiTree p,C;printf(“欢迎使用本二叉树程序,请按回车键继续.n“);getchar();printf(“正在构造空二叉树,请稍候 .“);printf(“n“);BiTree T;InitBiTree(T);if(BiTreeEmpty(T)printf(“构造空二叉树成功! n“);elseprintf(“构造空二叉树失败! n“);printf(“请按先序遍历顺序输入二叉树各结点的值!空结点用表示!n“);CreateBiTree(T);printf(“n“);getcha
20、r();printf(“请选择接下来的操作 :输入“1”为查看二叉树深度,输入“2”为查看二叉树根节点.n“);scanf(“%d“,if(i=1)printf(“此二叉树的深度为: %dnn“,BiTreeDepth(T);if(i=2)printf(“此二叉树的根节点为: %cnn“,Root(T);printf(“请选择遍历该二叉树的顺序:输入“1”为先序遍历,输入“2” 为中序遍历,输入“3” 为后序遍历,输入“4” 为层序遍历.n“);scanf(“%d“,getchar();printf(“n“);if(i=1)j=PreOrderTraverse(T,visit);printf(
21、“n“);if(j=0)printf(“该二叉树为空树,请重新运行程序!n“);if(i=2)j=InOrderTraverse(T,visit);printf(“n“);if(j=0)printf(“该二叉树为空树,请重新运行程序!n“);if(i=3)j=PostOrderTraverse(T,visit);printf(“n“);if(j=0)printf(“该二叉树为空树,请重新运行程序!n“);if(i=4)j=LevelOrderTraverse(T,visit);printf(“n“);if(j=0)printf(“该二叉树为空树,请重新运行程序!n“);printf(“n 请输
22、入需要替换的结点:n“);scanf(“%c“,getchar();p=Point(T,a);printf(“请输入需要代入的结点值: n“);scanf(“%c“,getchar();Assign(T,p,value);printf(“赋值之后该结点的值为: %cnn“,p-data);printf(“请输入“1”求该结点的双亲结点,输入“2” 求该结点的左孩子,输入“3”求该结点的右孩子,输入“4” 求该结点的左兄弟,输入“5”求该结点的右兄弟nn“);scanf(“%d“,getchar();switch(i)case 1:if(Parent(T,value)=NULL)printf(“
23、该结点没有双亲结点。n“);elseprintf(“该结点的双亲结点为:%cnn“,Parent(T,value);break;case 2:if(LeftChild(T,value)=NULL)printf(“该结点没有左孩子结点。n“);elseprintf(“该结点的左孩子结点为:%cnn“,LeftChild(T,value);break;case 3:if(RightChild(T,value)=NULL)printf(“该结点没有右孩子结点。n“);elseprintf(“该结点的右孩子结点为:%cnn“,RightChild(T,value);break;case 4:if(Le
24、ftSibling(T,value)=NULL)printf(“该结点没有左兄弟。n“);elseprintf(“该结点的左兄弟为:%cnn“,LeftSibling(T,value);break;case 5:if(RightSibling(T,value)=NULL)printf(“该结点没有右兄弟。n“);elseprintf(“该结点的右兄弟为:%cnn“,RightSibling(T,value);break;printf(“n 现在进行结点插入子树,请按照先序遍历的顺序输入二叉树C,注意该二叉树没有右子树!n“);InitBiTree(C);CreateBiTree(C);getc
25、har();printf(“n 请输入您需要插入子树的结点:n“);scanf(“%c“,getchar();p=Point(T,a);printf(“n 输入 0 示插入 C 为%c 结点的左子树而该结点原来的左子树变为 c 的右子树 .“,a);printf(“n 输入 1 示插入 C 为%c 结点的右子树而该结点原来的左子树变为 c 的右子树 ,请选择 .n“,a);scanf(“%d“, getchar();j= InsertChild(T, p, LR, C);if(j=0)printf(“插入失败! n“);elseprintf(“插入成功!该新二叉树的先序遍历为:“);PreOr
26、derTraverse(T, visit);printf(“nn 进行删除操作,请输入需要删除左子树或者右子树的结点:“);scanf(“%c“,getchar();p=Point(T,a);printf(“n 输入 0 表示删除%c 结点的左子树, 1 表示删除%c 结点的右子树,请选择.n“,a);scanf(“%d“, getchar();j = DeleteChild(T, p, LR);if(j=0)printf(“删除失败! n“);elseprintf(“删除成功!该新二叉树的先序遍历为:“);PreOrderTraverse(T, visit);DestroyTree(T);i
27、f (!T)printf(“n 树已被成功销毁!程序执行完毕,请按回车键n“); elseprintf(“n 树销毁不成功!程序执行完毕,请按回车键n“);getchar();for(i=1;i=4;+i)printf(“n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ * 感谢使用 *n“);printf(“ * * * *n“);printf(“ * 计科四班 *n“);printf(“ *
28、*n“);printf(“ *制作人:罗志权 *n“);printf(“ * *n“);printf(“ *学号:3111005843*n“);printf(“ * *n“);printf(“ *请按回车键退出程序*n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);printf(“ *n“);getchar();return OK;4.程序清单(计算机打印) ,输入的数据及各基本操作的测试结果;開始:第一步:手动创建二叉树:第二步:选择操作,这里选择查看深度:第三步:选择遍历方法,这里选择中序遍历
29、:第五步:替换某个结点:第六步:求该结点的邻近结点,这里选择右孩子:第七步:插入子树 C 到 e 结点作为 e 结点的左子树:第八步:删除结点的左子树或者右子树:程序执行完毕:显示作者:六.实验总结和体会。抽象数据类型是模块化思想的发展,有助于我们从更抽象的高度去讨论算法和数据结构的问题。通过这次实验,我对二叉树的抽象数据类型更加了解和熟悉,我们只需关心它的逻辑特征而不需要了解它的存储方式。数据结构是每个程序员的必修课,但是我们还要学的还有很多很多,因为在设计程序的时候会遇到很多的 BUG,这些 BUG 都是要靠自己慢慢去了解慢慢去调试才能解决的。而且现在计算机技术发展迅速,我们要学的可以说是无穷无尽的。