第六次数据结构作业
一、实验目的
1、掌握二叉树的基本特性
2、掌握二叉树的先序、中序、后序的递归遍历算法
3、理解二叉树的先序、中序、后序的非递归遍历算法
4、通过求二叉树的深度、叶子结点数和层序遍历等算法,理解二叉树的基本特性
二、实验预习
说明以下概念
1、二叉树:
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。
二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点。
2、递归遍历:
由于二叉树所具有的递归性质,一棵非空的二叉树可以看作是由根节点、左子树和右子树3部分构成,因为若能依次遍历这3部分的信息,也就遍历了整个二叉树。按照左子树的遍历在右子树的遍历之前进行的约定,根访问根节点位置的不同,可以得到二叉的前序、中序、后序3种遍历方法。
3、 非递归遍历:
不采用递归的方式对二叉树进行遍历,要采用栈去模拟实现。
4、层序遍历:
除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
三、实验内容和要求
1、阅读并运行下面程序,根据输入写出运行结果,并画出二叉树的形态。
#include<iostream> #include<conio.h> #define MAX 20 typedef struct BTNode{ /*节点结构声明*/ char data ; /*节点数据*/ struct BTNode *lchild; struct BTNode *rchild ; /*指针*/ }*BiTree; void createBiTree(BiTree *t){ /* 先序遍历创建二叉树*/ char s; BiTree q; printf("\nplease input data:(exit for #)"); s=getche(); if(s=='#'){*t=NULL; return;} q=(BiTree)malloc(sizeof(struct BTNode)); if(q==NULL){printf("Memory alloc failure!"); exit(0);} q->data=s; *t=q; createBiTree(&q->lchild); /*递归建立左子树*/ createBiTree(&q->rchild); /*递归建立右子树*/ } void PreOrder(BiTree p){ /* 先序遍历二叉树*/ if ( p!= NULL ) { printf("%c", p->data); PreOrder( p->lchild ) ; PreOrder( p->rchild) ; } } void InOrder(BiTree p){ /* 中序遍历二叉树*/ if( p!= NULL ) { InOrder( p->lchild ) ; printf("%c", p->data); InOrder( p->rchild) ; } } void PostOrder(BiTree p){ /* 后序遍历二叉树*/ if ( p!= NULL ) { PostOrder( p->lchild ) ; PostOrder( p->rchild) ; printf("%c", p->data); } } void Preorder_n(BiTree p){ /*先序遍历的非递归算法*/ BiTree stack[MAX],q; int top=0,i; for(i=0;i<MAX;i++) stack[i]=NULL;/*初始化栈*/ q=p; while(q!=NULL){ printf("%c",q->data); if(q->rchild!=NULL) stack[top++]=q->rchild; if(q->lchild!=NULL) q=q->lchild; else if(top>0) q=stack[--top]; else q=NULL; } } void release(BiTree t){ /*释放二叉树空间*/ if(t!=NULL){ release(t->lchild); release(t->rchild); free(t); } } int main(){ BiTree t=NULL; createBiTree(&t); printf("\n\nPreOrder the tree is:"); PreOrder(t); printf("\n\nInOrder the tree is:"); InOrder(t); printf("\n\nPostOrder the tree is:"); PostOrder(t); printf("\n\n先序遍历序列(非递归):"); Preorder_n(t); release(t); return 0; }
运行程序
输入:
ABC##DE#G##F###
运行结果:
二叉树形态
2、在上题中补充求二叉树中求结点总数算法(提示:可在某种遍历过程中统计遍历的结点数),并在主函数中补充相应的调用验证正确性。
算法代码:
#include<iostream> #include<conio.h> #define MAX 20 typedef struct BTNode{ /*节点结构声明*/ char data ; /*节点数据*/ struct BTNode *lchild; struct BTNode *rchild ; /*指针*/ }*BiTree; void createBiTree(BiTree *t){ /* 先序遍历创建二叉树*/ char s; BiTree q; printf("\nplease input data:(exit for #)"); s=getche(); if(s=='#'){*t=NULL; return;} q=(BiTree)malloc(sizeof(struct BTNode)); if(q==NULL){printf("Memory alloc failure!"); exit(0);} q->data=s; *t=q; createBiTree(&q->lchild); /*递归建立左子树*/ createBiTree(&q->rchild); /*递归建立右子树*/ } void PreOrder(BiTree p){ /* 先序遍历二叉树*/ if ( p!= NULL ) { printf("%c", p->data); PreOrder( p->lchild ) ; PreOrder( p->rchild) ; } } void InOrder(BiTree p){ /* 中序遍历二叉树*/ if( p!= NULL ) { InOrder( p->lchild ) ; printf("%c", p->data); InOrder( p->rchild) ; } } void PostOrder(BiTree p){ /* 后序遍历二叉树*/ if ( p!= NULL ) { PostOrder( p->lchild ) ; PostOrder( p->rchild) ; printf("%c", p->data); } } void Preorder_n(BiTree p){ /*先序遍历的非递归算法*/ BiTree stack[MAX],q; int top=0,i; for(i=0;i<MAX;i++) stack[i]=NULL;/*初始化栈*/ q=p; while(q!=NULL){ printf("%c",q->data); if(q->rchild!=NULL) stack[top++]=q->rchild; if(q->lchild!=NULL) q=q->lchild; else if(top>0) q=stack[--top]; else q=NULL; } } void release(BiTree t){ /*释放二叉树空间*/ if(t!=NULL){ release(t->lchild); release(t->rchild); free(t); } } int PreOrder_num(BiTree p) { int j=0; BiTree stack[MAX],q; int top=0,i; for(i=0; i<MAX; i++) stack[i]=NULL; /*初始化栈*/ q=p; while(q!=NULL) { j++; if(q->rchild!=NULL) stack[top++]=q->rchild; if(q->lchild!=NULL) q=q->lchild; else if(top>0) q=stack[--top]; else q=NULL; } return j; } int main(){ BiTree t=NULL; createBiTree(&t); printf("\n\nPreOrder the tree is:"); PreOrder(t); printf("\n\nInOrder the tree is:"); InOrder(t); printf("\n\nPostOrder the tree is:"); PostOrder(t); printf("\n\n先序遍历序列(非递归):"); Preorder_n(t); printf("\n\n结点总数:"); printf("%d",PreOrder_num(t)); release(t); return 0; }
运行结果:
3、在上题中补充求二叉树中求叶子结点总数算法(提示:可在某种遍历过程中统计遍历的叶子结点数),并在主函数中补充相应的调用验证正确性。
int num1=0 ,num2=0; if(p==NULL) return 0; else if(p->lchild==NULL&&p->rchild==NULL) return 1; else{ num1=LeafNodes(p->lchild) ; num2=LeafNodes(p->rchild) ; return (num1+num2); } } int main(){ BiTree t=NULL; createBiTree(&t); printf("\n\nPreOrder the tree is:"); PreOrder(t); printf("\n\nInOrder the tree is:"); InOrder(t); printf("\n\nPostOrder the tree is:"); PostOrder(t); printf("\n\n先序遍历序列(非递归):"); Preorder_n(t); printf("\n\n结点总数:"); printf("%d",PreOrder_num(t)); printf("\n\n叶结点总数:"); printf("%d",LeafNodes(t)); release(t); return 0; }
运行结果:
4、在上题中补充求二叉树深度算法,并在主函数中补充相应的调用验证正确性。
int lchilddep,rchilddep; if(p==NULL) return 0; else { lchilddep=BTNodeDepth(p->lchild); rchilddep=BTNodeDepth(p->rchild); return(lchilddep>rchilddep)?(lchilddep+1):(rchilddep+1); } } int main(){ BiTree t=NULL; createBiTree(&t); printf("\n\nPreOrder the tree is:"); PreOrder(t); printf("\n\nInOrder the tree is:"); InOrder(t); printf("\n\nPostOrder the tree is:"); PostOrder(t); printf("\n\n先序遍历序列(非递归):"); Preorder_n(t); printf("\n\n结点总数:"); printf("%d",PreOrder_num(t)); printf("\n\n树的深度:"); printf("%d",BTNodeDepth(t)); release(t); return 0; }
运行结果:
四、实验小结
通过求二叉树的深度、叶子结点数和层序遍历等算法,理解了二叉树的基本特性,具体代码实现仍需加强。