1、 数据结构实验报告 题目:二叉树抽象数据类型 学 院 计算机学院 专 业 计算机科学与技术 年级班别 学 号 学生姓名 指导教师 成 绩 ____________________ 2013年6月 一.实验概要 实验项目名称: 二叉树抽象数据类型的实现 实验项目性质: 设计性实验 所属课程名称: 数据结构 实验计划学时: 6 二.实验目的 1. 了解
2、二叉树的定义以及各项基本操作。 2. 实现二叉树存储、遍历及其他基本功能 三. 实验仪器设备和材料 硬件:PC机 软件:Visual C++ 6.0 四.实验的内容 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、
(3) 若D1≠∅,则D1中存在惟一的元素x1,
4、ion构造二叉树T。 ClearBiTree(&T); 初始条件:二叉树T存在。 操作结果:将二叉树T清为空树。 BiTreeEmpty(T); 初始条件:二叉树T存在。 操作结果:若T为空二叉树,则返回TURE,否则FALSE。 BiTreeDepth(T); 初始条件:二叉树T存在。 操作结果:返回T的深度。 Root(T); 初始条件:二叉树T存在。 操作结果:返回T的根。 Value(T,e); 初始条件:二叉树T存在,e是T中的某个结点。 操作结果:返回e的值。 Assign(T,&e,value); 初始条件:二叉树T存在,e是T中的某个结
5、点。 操作结果:结点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(T,e); 初始条件:二叉树T存在,e是T中的某个结点。 操作结果:返回e的左兄弟。若
6、e无左孩子或无左兄弟,则返回“空”。
RightSibling(T,e);
初始条件:二叉树T存在,e是T中的某个结点。
操作结果:返回e的右兄弟。若e无右孩子或无右兄弟,则返回“空”。
}ADT BinaryTree
2.存储结构:采用无头结点的链式存储结构实现
3.源代码:
头文件及存储结构:
#include
7、ZE 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 st
8、ruct { QueuePtr front; QueuePtr rear; }LinkQueue; //链队列结构体 算法设计: int InitQueue(LinkQueue &Q) //构造空队列 { Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode)); if(!Q.front) //存储分配失败 exit(OVERFLOW); Q.front->next = NULL; return OK; } int EnQu
9、eue(LinkQueue &Q, QElemType e) //新元素入队尾 { QueuePtr p; 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 &Q, QElemType &e) //删除队头元素 { QueuePt
10、r p; if(Q.front == 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)
11、return TURE; else return FALSE; } int InitBiTree(BiTree &T) // 构造空二叉树 { T = NULL; return OK; } int DestroyTree(BiTree &T) //销毁二叉树 { if(!T) return ERROR; else DestroyTree(T->lchild); DestroyTree(T->rchild); free(T); T=NULL; return OK; } void CreateBiTr
12、ee(BiTree &T) //用先序遍历的方式构建二叉树,以‘@’表示空结点。 { TElemType ch; scanf("%c",&ch); if(ch=='@') T=NULL; else { if(!(T=(BiTree)malloc(sizeof(BiTNode)))) exit(OVERFLOW); //分配存储空间失败 T->data=ch; CreateBiTree(T->lchild); //构造左子树 CreateBiTree(T->rchild); //构造右子树 } } int Clea
13、rBiTree(BiTree &T) //清空二叉树函数 { if(!T) return ERROR; else { ClearBiTree(T->lchild); ClearBiTree(T->rchild); free(T); T=NULL; return OK; } } int BiTreeEmpty(BiTree T) //判断二叉树是否为空 { if(!T) return TURE; else return FALSE; } int BiTreeDepth(BiTree T) //计算二
14、叉树深度 { int lcd,rcd; if(!T) return 0; lcd=BiTreeDepth(T->lchild); rcd=BiTreeDepth(T->rchild); return ((lcd>rcd?lcd:rcd)+1); } TElemType Root(BiTree T) //判断二叉树是否空,若非空返回其根 { if(BiTreeEmpty(T)) return NULL; else return (T->data); } TElemType Value(BiTree T,BiTree e) //
15、返回e结点的值 { return e->data; } int Assign(BiTree T,BiTree &e,TElemType value) // 将value的值给结点e { e->data=value; return OK; } TElemType Parent(BiTree T,TElemType e) {//返回双亲 LinkQueue q; QElemType a; if(T) { InitQueue(q); EnQueue(q,T);//树根入队列 while(!QueueEmpty(q))//队不空
16、 { DeQueue (q, a);//出队,队列元素赋给a if(a->lchild&&a->lchild->data==e||a->rchild&&a->rchild->data==e) //找到e return a->data; //返回双亲的值 else { if(a->lchild) EnQueue(q,a->lchild);//入队列左孩子 if(a->rchild) EnQueue(q,a->rchild);//入队列右孩子 } } } return NULL; }
17、 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) { EnQueue(q,a->lchild); } if(a->rc
18、hild) { EnQueue(q,a->rchild); } } } return NULL; } TElemType LeftChild(BiTree T,TElemType e) {//返回e的左孩子 BiTree a; if(T) { a=Point(T,e);//a是指向结点e的指针 if(a&&a->lchild) return a->lchild->data; } return NULL; } TElemType RightChild(BiTree T,
19、TElemType e) //返回e的右孩子 { BiTree a; if(T) { if((a=Point(T,e))&&a->rchild) return a->rchild->data; } return NULL; } TElemType LeftSibling(BiTree T,TElemType e) { //返回左兄弟 TElemType a; BiTree p; if(T) { a=Parent(T,e);//a为e的双亲 if(a!=NULL) { p=Point(T,a);//p
20、指向结点a的指针 if(p->lchild&&p->rchild&&p->rchild->data==e)//p存在左右孩子而且右孩子是e return p->lchild->data; } } return 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指向结
21、点a的指针 if(p->lchild&&p->rchild&&p->lchild->data==e)//p存在左右孩子而且左孩子是e return p->rchild->data; } } return NULL; } int InsertChild(BiTree T,BiTree p,int LR,BiTree c) //根据LR为0或者1,插入C为T中P所指结点的左或者右子树, //P所指的结点原有左或右子树则成为C的右子树 { if(p) { if(LR==0) //把二叉树C插入p所指结点的左子树
22、{ c->rchild=p->lchild; p->lchild=c; } else { c->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); } else { ClearBiTree(p->rchild);
23、 } 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;
24、 } return ERROR; } int InOrderTraverse(BiTree T,void(*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)) { //后序
25、遍历二叉树 if(T) { PostOrderTraverse(T->lchild,visit); PostOrderTraverse(T->rchild,visit); visit(T->data); return OK; } return ERROR; } int LevelOrderTraverse(BiTree T,void(*visit)(TElemType)) {//层序遍历二叉树 LinkQueue q; QElemType a; if(T) { InitQueue(q);//初始化队列 EnQ
26、ueue(q,T);//根指针入队 while(!QueueEmpty(q)) { DeQueue(q,a);//出队元素,赋给a visit(a->data);//访问a所指结点 if(a->lchild!=NULL) EnQueue(q,a->lchild); if(a->rchild!=NULL) EnQueue(q,a->rchild); } return OK; } return ERROR; } 主函数: int main() { int i,j,LR; TElemType
27、value,a,temp; BiTree p,C; printf("欢迎使用本二叉树程序,请按回车键继续...\n"); getchar(); printf("正在构造空二叉树,请稍候..."); printf("\n"); BiTree T; InitBiTree(T); if(BiTreeEmpty(T)) printf("构造空二叉树成功!\n"); else printf("构造空二叉树失败!\n"); printf("请按先序遍历顺序输入二叉树各结点的值!空结点用@表示!\n"); CreateBiTree(T); prin
28、tf("\n"); getchar(); printf("请选择接下来的操作:输入“1”为查看二叉树深度,输入“2”为查看二叉树根节点...\n"); scanf("%d",&i); if(i==1) printf("此二叉树的深度为:%d\n\n",BiTreeDepth(T)); if(i==2) printf("此二叉树的根节点为:%c\n\n",Root(T)); printf("请选择遍历该二叉树的顺序:输入“1”为先序遍历,输入“2”为中序遍历,输入“3”为后序遍历,输入“4”为层序遍历...\n"); scanf("%d",&i); g
29、etchar(); printf("\n"); if(i==1) { j=PreOrderTraverse(T,visit); printf("\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);
30、 printf("\n"); if(j==0) printf("该二叉树为空树,请重新运行程序!\n"); } if(i==4) { j=LevelOrderTraverse(T,visit); printf("\n"); if(j==0) printf("该二叉树为空树,请重新运行程序!\n"); } printf("\n请输入需要替换的结点:\n"); scanf("%c",&a); getchar(); p=Point(T,a); printf("请输入需要代入的结点值:\n"); scanf("%c",&va
31、lue); getchar(); Assign(T,p,value); printf("赋值之后该结点的值为:%c\n\n",p->data); printf("请输入“1”求该结点的双亲结点,输入“2”求该结点的左孩子,输入“3”求该结点的右孩子,输入“4”求该结点的左兄弟,输入“5”求该结点的右兄弟..\n\n"); scanf("%d",&i); getchar(); switch(i) { case 1: { if(Parent(T,value)==NULL) printf("该结点没有双亲结点。\n");
32、else printf("该结点的双亲结点为:%c\n\n",Parent(T,value));break; } case 2: { if(LeftChild(T,value)==NULL) printf("该结点没有左孩子结点。\n"); else printf("该结点的左孩子结点为:%c\n\n",LeftChild(T,value));break; } case 3: { if(RightChild(T,value)==NULL) printf("该结点没有右孩
33、子结点。\n"); else printf("该结点的右孩子结点为:%c\n\n",RightChild(T,value));break; } case 4: { if(LeftSibling(T,value)==NULL) printf("该结点没有左兄弟。\n"); else printf("该结点的左兄弟为:%c\n\n",LeftSibling(T,value)); break; } case 5: { if(RightSibling(T,value)==N
34、ULL) printf("该结点没有右兄弟。\n"); else printf("该结点的右兄弟为:%c\n\n",RightSibling(T,value)); break; } } printf("\n现在进行结点插入子树,请按照先序遍历的顺序输入二叉树C,注意该二叉树没有右子树!\n"); InitBiTree(C); CreateBiTree(C); getchar(); printf("\n请输入您需要插入子树的结点:\n"); scanf("%c",&a); getchar(); p=Point
35、T,a); printf("\n输入0示插入C为%c结点的左子树而该结点原来的左子树变为c的右子树...",a); printf("\n输入1示插入C为%c结点的右子树而该结点原来的左子树变为c的右子树,请选择...\n",a); scanf("%d", &LR); getchar(); j= InsertChild(T, p, LR, C); if(j==0) { printf("插入失败!\n"); } else { printf("插入成功!该新二叉树的先序遍历为:"); PreOrderTraverse(T, visit);
36、 } printf("\n\n进行删除操作,请输入需要删除左子树或者右子树的结点:"); scanf("%c",&a); getchar(); p=Point(T,a); printf("\n输入 0 表示删除%c结点的左子树, 1 表示删除%c结点的右子树,请选择...\n",a); scanf("%d", &LR); getchar(); j = DeleteChild(T, p, LR); if(j==0) { printf("删除失败!\n"); } else { printf("删除成功!该新二叉树的先序遍历为:");
37、 PreOrderTraverse(T, visit); } DestroyTree(T); if (!T) printf("\n树已被成功销毁!程序执行完毕,请按回车键\n"); else printf("\n树销毁不成功!程序执行完毕,请按回车键\n"); getchar(); for(i=1;i<=4;++i) printf("\n"); printf(" ***************************************************************************\n"); prin
38、tf(" ***************************************************************************\n"); printf(" ***************************************************************************\n"); printf(" ***************************************************************************\n"); printf(" *******************
39、\n"); printf(" ***************************************************************************\n"); printf(" ***************************************************************************\n"); printf(" *******************************************
40、\n"); printf(" ****************************** 感谢使用 *****************************\n"); printf(" ****************************** * * *****************************\n"); printf(" ****************************** 计科四班 *****************************
41、\n"); printf(" ****************************** *****************************\n"); printf(" ******************************制作人:罗志权 *****************************\n"); printf(" ****************************** *****************************\n"); printf(" **************
42、学号:3111005843*****************************\n"); printf(" ***************************** *****************************\n"); printf(" *****************************请按回车键退出程序****************************\n"); printf(" **************************************************
43、\n"); printf(" ***************************************************************************\n"); printf(" ***************************************************************************\n"); printf(" **************************************************************************
44、\n"); printf(" ***************************************************************************\n"); printf(" ***************************************************************************\n"); getchar(); return OK; } 4.程序清单(计算机打印),输入的数据及各基本操作的测试结果; 開始: 第一步:手动创建二叉树: 第二步:选择操作,这里
45、选择查看深度: 第三步:选择遍历方法,这里选择中序遍历: 第五步:替换某个结点: 第六步:求该结点的邻近结点,这里选择右孩子: 第七步:插入子树C到e结点作为e结点的左子树: 第八步:删除结点的左子树或者右子树: 程序执行完毕: 显示作者: 六.实验总结和体会。 抽象数据类型是模块化思想的发展,有助于我们从更抽象的高度去讨论算法和数据结构的问题。通过这次实验,我对二叉树的抽象数据类型更加了解和熟悉,我们只需关心它的逻辑特征而不需要了解它的存储方式。数据结构是每个程序员的必修课,但是我们还要学的还有很多很多,因为在设计程序的时候会遇到很多的BUG,这些BUG都是要靠自己慢慢去了解慢慢去调试才能解决的。而且现在计算机技术发展迅速,我们要学的可以说是无穷无尽的。 THANKS !!! 致力为企业和个人提供合同协议,策划案计划书,学习课件等等 打造全网一站式需求 欢迎您的下载,资料仅供参考






