求二叉树高度,叶子结点及前序遍历
二叉树的建立与先序中序后序遍历 求叶子节点个数 求分支节点个数 求二叉树的高度

/*一下总结一些二叉树的常见操作:包括建立二叉树先/中/后序遍历二叉树求二叉树的叶子节点个数求二叉树的单分支节点个数计算二叉树双分支节点个数计算二叉树的高度计算二叉树的所有叶子节点数*/#include<stdio.h> //c语言的头文件#include<stdlib.h>//c语言的头文件stdlib.h千万别写错了#define Maxsize 100/*创建二叉树的节点*/typedef struct BTNode //结构体struct 是关键字不能省略结构体名字可以省略(为无名结构体)//成员类型可以是基本型或者构造形,最后的为结构体变量。
{char data;struct BTNode *lchild,*rchild;}*Bitree;/*使用先序建立二叉树*/Bitree Createtree() //树的建立{char ch;Bitree T;ch=getchar(); //输入一个二叉树数据if(ch==' ') //' '中间有一个空格的。
T=NULL;else{ T=(Bitree)malloc(sizeof(Bitree)); //生成二叉树(分配类型*)malloc(分配元素个数*sizeof(分配类型))T->data=ch;T->lchild=Createtree(); //递归创建左子树T->rchild=Createtree(); //地柜创建右子树}return T;//返回根节点}/*下面先序遍历二叉树*//*void preorder(Bitree T) //先序遍历{if(T){printf("%c-",T->data);preorder(T->lchild);preorder(T->rchild);}} *//*下面先序遍历二叉树非递归算法设计*/void preorder(Bitree T) //先序遍历非递归算法设计{Bitree st[Maxsize];//定义循环队列存放节点的指针Bitree p;int top=-1; //栈置空if(T){top++;st[top]=T; //根节点进栈while(top>-1) //栈不空时循环{p=st[top]; //栈顶指针出栈top--;printf("%c-",p->data );if(p->rchild !=NULL) //右孩子存在进栈{top++;st[top]=p->rchild ;}if(p->lchild !=NULL) //左孩子存在进栈{top++;st[top]=p->lchild ;}}printf("\n");}}/*下面中序遍历二叉树*//*void inorder(Bitree T) //中序遍历{if(T){inorder(T->lchild);printf("%c-",T->data);inorder(T->rchild);}}*//*下面中序遍历二叉树非递归算法设计*/void inorder(Bitree T) //中序遍历{Bitree st[Maxsize]; //定义循环队列,存放节点的指针Bitree p;int top=-1;if(T){p=T;while (top>-1||p!=NULL) //栈不空或者*不空是循环{while(p!=NULL) //扫描*p的所有左孩子并进栈{top++;st[top]=p;p=p->lchild ;}if(top>-1){p=st[top]; //出栈*p节点,它没有右孩子或右孩子已被访问。
二叉树的性质及其遍历

12.3.1 顺序存储结构 12.3.2 链式存储
•二叉树的性质及其遍历
12.1 二叉树的基本性质
定理 1:满二叉树第i层上恰好有2i-1个结点 (i≥1).
证:使用归纳法。i=1时,结论显然成立。设i=k时结 论成立,则考虑i=k+1的情形。由于(k+1)层上结点 是k层上结点的儿子,而且满二叉树每个非叶子结 点恰好有两个儿子,故(k+1)层上结点个数为k层上 结点个数的2倍,即2·2k-1 = 2k = 2(k+1)-1. 这表明, i=k+1时结论也成立。由归纳法原理,结论对任意 的k都成立,证毕。
x的相对地址x的编号x的父亲/儿子的编 号(性质7) x的父亲/儿子的相对地址。
•二叉树的性质及其遍历
至于结点的相对地址与编号之间的换算,有下列关系: 结点相对地址 = (结点编号 – 1)×每个结点所
占单元数目
a
b
f
cegh d
1 2 34 56 7 8 a b f ce g h d …
图 12-2 顺序二叉树的顺序存储
•二叉树的性质及其遍历
12.1.7 定理7 若对一棵有n个结点的顺序二叉树的结点按层序 编号,则对任一结点i(1≤i≤n),有(1)若i=1, 则结点i是根, 无父亲;若i〉1,则其父亲是结点i/2。(2)若2i>n,则结点i 无左儿子(从而也无右儿子,为叶子);否则i的左儿子是结 点2i。(3)若2i+1>n,则结点i无右儿子;否则右儿子是结点 2i+1。
12.3.1顺序存储结构
(一) 顺序二叉树的顺序存储结构
这种存储结构是按结点的层序编号的次序,将 结点存储在一片连续存储区域内。由定理 7知, 对顺序二叉树,若已知结点的层序编号,则可推 算出它的父亲和儿子的编号,所以,在这种存储 结构中,很容易根据结点的相对地址计算出它的 父亲和儿子的相对地址,方法是:
二叉树的遍历及常用算法

⼆叉树的遍历及常⽤算法⼆叉树的遍历及常⽤算法遍历的定义:按照某种次序访问⼆叉树上的所有结点,且每个节点仅被访问⼀次;遍历的重要性:当我们需要对⼀颗⼆叉树进⾏,插⼊,删除,查找等操作时,通常都需要先遍历⼆叉树,所有说:遍历是⼆叉树的基本操作;遍历思路:⼆叉树的数据结构是递归定义(每个节点都可能包含相同结构的⼦节点),所以遍历也可以使⽤递归,即结点不为空则继续递归调⽤每个节点都有三个域,数据与,左孩⼦指针和右孩⼦之指针,每次遍历只需要读取数据,递归左⼦树,递归右⼦树,这三个操作三种遍历次序:根据访问三个域的不同顺序,可以有多种不同的遍历次序,⽽通常对于⼦树的访问都按照从左往右的顺序;设:L为遍历左⼦树,D为访问根结点,R为遍历右⼦树,且L必须位于R的前⾯可以得出以下三种不同的遍历次序:先序遍历操作次序为DLR,⾸先访问根结点,其次遍历根的左⼦树,最后遍历根右⼦树,对每棵⼦树同样按这三步(先根、后左、再右)进⾏中序遍历操作次序为LDR,⾸先遍历根的左⼦树,其次访问根结点,最后遍历根右⼦树,对每棵⼦树同样按这三步(先左、后根、再右)进⾏后序遍历操作次序为LRD,⾸先遍历根的左⼦树,其次遍历根的右⼦树,最后访问根结点,对每棵⼦树同样按这三步(先左、后右、最后根)进⾏层次遍历层次遍历即按照从上到下从左到右的顺序依次遍历所有节点,实现层次遍历通常需要借助⼀个队列,将接下来要遍历的结点依次加⼊队列中;遍历的应⽤“遍历”是⼆叉树各种操作的基础,可以在遍历过程中对结点进⾏各种操作,如:对于⼀棵已知⼆叉树求⼆叉树中结点的个数求⼆叉树中叶⼦结点的个数;求⼆叉树中度为1的结点个数求⼆叉树中度为2的结点个数5求⼆叉树中⾮终端结点个数交换结点左右孩⼦判定结点所在层次等等...C语⾔实现:#include <stdio.h>//⼆叉链表数据结构定义typedef struct TNode {char data;struct TNode *lchild;struct TNode *rchild;} *BinTree, BinNode;//初始化//传⼊⼀个指针令指针指向NULLvoid initiate(BinTree *tree) {*tree = NULL;}//创建树void create(BinTree *BT) {printf("输⼊当前结点值: (0则创建空节点)\n");char data;scanf(" %c", &data);//连续输⼊整形和字符时.字符变量会接受到换⾏,所以加空格if (data == 48) {*BT = NULL;return;} else {//创建根结点//注意开辟的空间⼤⼩是结构体的⼤⼩⽽不是结构体指针⼤⼩,写错了不会⽴马产⽣问题,但是后续在其中存储数据时极有可能出现内存访问异常(飙泪....) *BT = malloc(sizeof(struct TNode));//数据域赋值(*BT)->data = data;printf("输⼊节点 %c 的左孩⼦ \n", data);create(&((*BT)->lchild));//递归创建左⼦树printf("输⼊节点 %c 的右孩⼦ \n", data);create(&((*BT)->rchild));//递归创建右⼦树}}//求双亲结点(⽗结点)BinNode *Parent(BinTree tree, char x) {if (tree == NULL)return NULL;else if ((tree->lchild != NULL && tree->lchild->data == x) || (tree->rchild != NULL && tree->rchild->data == x))return tree;else{BinNode *node1 = Parent(tree->lchild, x);BinNode *node2 = Parent(tree->rchild, x);return node1 != NULL ? node1 : node2;}}//先序遍历void PreOrder(BinTree tree) {if (tree) {//输出数据printf("%c ", tree->data);//不为空则按顺序继续递归判断该节点的两个⼦节点PreOrder(tree->lchild);PreOrder(tree->rchild);}}//中序void InOrder(BinTree tree) {if (tree) {InOrder(tree->lchild);printf("%c ", tree->data);InOrder(tree->rchild);}}//后序void PostOrder(BinTree tree) {if (tree) {PostOrder(tree->lchild);PostOrder(tree->rchild);printf("%c ", tree->data);}}//销毁结点递归free所有节点void DestroyTree(BinTree *tree) {if (*tree != NULL) {printf("free %c \n", (*tree)->data);if ((*tree)->lchild) {DestroyTree(&((*tree)->lchild));}if ((*tree)->rchild) {DestroyTree(&((*tree)->rchild));}free(*tree);*tree = NULL;}}// 查找元素为X的结点使⽤的是层次遍历BinNode *FindNode(BinTree tree, char x) {if (tree == NULL) {return NULL;}//队列BinNode *nodes[1000] = {};//队列头尾位置int front = 0, real = 0;//将根节点插⼊到队列尾nodes[real] = tree;real += 1;//若队列不为空则继续while (front != real) {//取出队列头结点输出数据BinNode *current = nodes[front];if (current->data == x) {return current;}front++;//若当前节点还有⼦(左/右)节点则将结点加⼊队列if (current->lchild != NULL) {nodes[real] = current->lchild;real++;}if (current->rchild != NULL) {nodes[real] = current->rchild;real++;}}return NULL;}//层次遍历// 查找元素为X的结点使⽤的是层次遍历void LevelOrder(BinTree tree) {if (tree == NULL) {return;}//队列BinNode *nodes[1000] = {};//队列头尾位置int front = 0, real = 0;//将根节点插⼊到队列尾nodes[real] = tree;real += 1;//若队列不为空则继续while (front != real) {//取出队列头结点输出数据BinNode *current = nodes[front];printf("%2c", current->data);front++;//若当前节点还有⼦(左/右)节点则将结点加⼊队列if (current->lchild != NULL) {nodes[real] = current->lchild;real++;}if (current->rchild != NULL) {nodes[real] = current->rchild;real++;}}}//查找x的左孩⼦BinNode *Lchild(BinTree tree, char x) {BinTree node = FindNode(tree, x);if (node != NULL) {return node->lchild;}return NULL;}//查找x的右孩⼦BinNode *Rchild(BinTree tree, char x) {BinTree node = FindNode(tree, x);if (node != NULL) {return node->rchild;}return NULL;}//求叶⼦结点数量int leafCount(BinTree *tree) {if (*tree == NULL)return 0;//若左右⼦树都为空则该节点为叶⼦,且后续不⽤接续递归了else if (!(*tree)->lchild && !(*tree)->rchild)return 1;else//若当前结点存在⼦树,则递归左右⼦树, 结果相加return leafCount(&((*tree)->lchild)) + leafCount(&((*tree)->rchild));}//求⾮叶⼦结点数量int NotLeafCount(BinTree *tree) {if (*tree == NULL)return 0;//若该结点左右⼦树均为空,则是叶⼦,且不⽤继续递归else if (!(*tree)->lchild && !(*tree)->rchild)return 0;else//若当前结点存在左右⼦树,则是⾮叶⼦结点(数量+1),在递归获取左右⼦树中的⾮叶⼦结点,结果相加 return NotLeafCount(&((*tree)->lchild)) + NotLeafCount(&((*tree)->rchild)) + 1;}//求树的⾼度(深度)int DepthCount(BinTree *tree) {if (*tree == NULL)return 0;else{//当前节点不为空则深度+1 在加上⼦树的⾼度,int lc = DepthCount(&((*tree)->lchild)) + 1;int rc = DepthCount(&((*tree)->rchild)) + 1;return lc > rc?lc:rc;// 取两⼦树深度的最⼤值 }}//删除左⼦树void RemoveLeft(BinNode *node){if (!node)return;if (node->lchild)DestroyTree(&(node->lchild));node->lchild = NULL;}//删除右⼦树void RemoveRight(BinNode *node){if (!node)return;if (node->rchild)DestroyTree(&(node->rchild));node->rchild = NULL;}int main() {BinTree tree;create(&tree);BinNode *node = Parent(tree, 'G');printf("G的⽗结点为%c\n",node->data);BinNode *node2 = Lchild(tree, 'D');printf("D的左孩⼦结点为%c\n",node2->data);BinNode *node3 = Rchild(tree, 'D');printf("D的右孩⼦结点为%c\n",node3->data);printf("先序遍历为:");PreOrder(tree);printf("\n");printf("中序遍历为:");InOrder(tree);printf("\n");printf("后序遍历为:");PostOrder(tree);printf("\n");printf("层次遍历为:");LevelOrder(tree);printf("\n");int a = leafCount(&tree);printf("叶⼦结点数为%d\n",a);int b = NotLeafCount(&tree);printf("⾮叶⼦结点数为%d\n",b);int c = DepthCount(&tree);printf("深度为%d\n",c);//查找F节点BinNode *node4 = FindNode(tree,'C');RemoveLeft(node4);printf("删除C的左孩⼦后遍历:");LevelOrder(tree);printf("\n");RemoveRight(node4);printf("删除C的右孩⼦后遍历:");LevelOrder(tree);printf("\n");//销毁树printf("销毁树 \n");DestroyTree(&tree);printf("销毁后后遍历:");LevelOrder(tree);printf("\n");printf("Hello, World!\n");return 0;}测试:测试数据为下列⼆叉树:运⾏程序复制粘贴下列内容:ABDGHECKFIJ特别感谢:iammomo。
实验五 二叉树的应用----表达式求值

浙江大学城市学院实验报告课程名称python高级程序设计实验项目名称实验五二叉树的应用----表达式求值实验成绩指导老师(签名)日期一.实验目的和要求1、掌握二叉树的链式存储结构;2、掌握在二叉链表上的二叉树的基本操作;3、掌握二叉树的简单应用----表达式树的操作。
二.实验内容1、在实验四中,已经实现了对一个中缀表达式可以用栈转换成后缀表达式,并可对后缀表达式进行求值计算的方法。
另一种思路是可以利用二叉树建立表达式树,通过对该表达式树进行求值计算,本实验实现:输入一个中缀表达式,建立该表达式的二叉树,然后对该二叉树进行表达式值的计算。
如一个中缀达式(6+2)*5 的二叉树表示为如下所示时,该二叉树的后序遍历62+5*正好就是后缀表达式。
设一般数学表达式的运算符包括+、-、*、/ 四种,当然允许(),且()优先级高。
为方便实现,设定输入的表达式只允许个位整数。
要求设计一个完整的程序,对输入的一个日常的中缀表达式,实现以下功能:⏹建立对应的二叉树⏹输出该二叉树的前序序列、中序序列、后序序列⏹求该二叉树的高度⏹求该二叉树的结点总数⏹求该二叉树的叶子结点数⏹计算该二叉树的表达式值分析:(1)表达式树的构建方法:●构建表达式树的方法之一:直接根据输入的中缀表达式构建对于任意一个算术中缀表达式,都可用二叉树来表示。
表达式对应的二叉树创建后,利用二叉树的遍历等操作,很容易实现二叉树的求值运算。
因此问题的关键就是如何创建表达式树。
对于一个中缀表达式来说,其表达式对应的表达式树中叶子结点均为操作数,分支结点均为运算符。
由于创建的表达式树需要准确的表达运算次序,因此,在扫描表达式创建表达式树的过程中,当遇到运算符时不能直接创建结点,而应将其与前面的运算符进行优先级比较,根据比较结果进行处理。
这种处理方式在实验四中以采用过,可以借助一个运算符栈,来暂存已经扫描到的还未处理的运算符。
根据表达式树与表达式对应关系的递归定义,每两个操作数和一个运算符就可以建立一棵表达式二叉树,而该二叉树又可以作为另一个运算符结点的一棵子树。
数据结构课后习题答案及解析第六章

第六章树和二叉树(下载后用阅读版式视图或web版式可以看清)习题一、选择题1.有一“遗传”关系:设x是y的父亲,则x可以把它的属性遗传给y。
表示该遗传关系最适合的数据结构为( )。
A.向量B.树 C图 D.二叉树2.树最合适用来表示( )。
A.有序数据元素 B元素之间具有分支层次关系的数据C无序数据元素 D.元素之间无联系的数据3.树B的层号表示为la,2b,3d,3e,2c,对应于下面选择的( )。
A. la (2b (3d,3e),2c)B. a(b(D,e),c)C. a(b(d,e),c)D. a(b,d(e),c)4.高度为h的完全二叉树至少有( )个结点,至多有( )个结点。
A. 2h_lB.h C.2h-1 D. 2h5.在一棵完全二叉树中,若编号为f的结点存在右孩子,则右子结点的编号为( )。
A. 2iB. 2i-lC. 2i+lD. 2i+26.一棵二叉树的广义表表示为a(b(c),d(e(,g(h)),f)),则该二叉树的高度为 ( )。
A.3B.4C.5D.67.深度为5的二叉树至多有( )个结点。
A. 31B. 32C. 16D. 108.假定在一棵二叉树中,双分支结点数为15,单分支结点数为30个,则叶子结点数为( )个。
A. 15B. 16C. 17D. 479.题图6-1中,( )是完全二叉树,( )是满二叉树。
..专业知识编辑整理..10.在题图6-2所示的二叉树中:(1)A结点是A.叶结点 B根结点但不是分支结点 C根结点也是分支结点 D.分支结点但不是根结点(2)J结点是A.叶结点 B.根结点但不是分支结点 C根结点也是分支结点 D.分支结点但不是根结点(3)F结点的兄弟结点是A.EB.D C.空 D.I(4)F结点的双亲结点是A.AB.BC.CD.D(5)树的深度为A.1B.2C.3D.4(6)B结点的深度为A.1B.2C.3D.4(7)A结点所在的层是A.1B.2C.3D.4..专业知识编辑整理..11.在一棵具有35个结点的完全二叉树中,该树的深度为( )。
山大数据结构实验报告二叉树

实验报告实验内容:二叉树的建立与基本操作1.二叉树的遍历基本思想:二叉树是由三个基本单元组成:根节点、左子树和右子树。
因此若能依次遍历这三部分,便是遍历了整棵二叉树。
可采用递归调用来实现。
(1)先序遍历若二叉树为空,则空操作;否则访问根节点;先序遍历左子树;先序遍历右子树。
(2)中序遍历若二叉树为空,则空操作;否则中序遍历左子树;访问根节点;中序遍历右子树。
(3)后序遍历若二叉树为空,则空操作;否则后序遍历左子树;后序遍历右子树;访问根节点。
(4)层次遍历若节点不为空,则访问该节点,并将其入列;接着从队列中取已被访问的,但其左右孩子尚未被访问的;访问该节点的左孩子,将其入列;访问该节点的右孩子,将其入列。
2.二叉树的建立基本思想:对二叉树遍历基本操作已经建立的基础上,在遍历过程中生成节点,建立二叉树存储结构,采用先序遍历建立二叉树链表:(1)按先序序列输入二叉树中节点的元素,以空格表示空,直到输入回车为止;(2)若元素值为空,则赋值NULL;否则生成一个新的节点,将元素值赋值给该根节点的数值域;(3)建立该根节点的左子树;(4)建立根节点的右子树。
BiTree CreateBiTree(BiTree T){//构造二叉树T,按先序序列输入二叉树中节点的值,空格表示空树char ch;if((ch=getchar())==’‘)T=NULL;elseif(ch!=’\n’){if(!(T=(BiTree)malloc(sizeof(BiTNode))))exit(1);T->data=ch;//生成根节点T->lchild=CreateBiTree(T->lchild);//构造左子树T->rchild=CreateBiTree(T->rchild);//构造右子树}return T;}3.二叉树的叶子数基本思想:(1)若该节点无孩子,则表示为叶子,计数器加一;(2)若该节点右孩子,求其左子树的叶子;(3)再求其右子树的叶子4.二叉树的高度基本思想:首先分析二叉树的深度(高度)和它的左、右子树深度之间的关系。
数据结构——- 二叉树

证明: 5.1 二叉树的概念
(1)总结点数为 ●二叉树的主要性质 n=n0+n1+n2 (2)除根结点外,每个 ●性质3: 结点都有一个边e进入 任何一棵二叉树,若其终端结点数为n0, n=e+1 度为2的结点数为n2,则n0=n2+1 (3)边e又是由度为1或2 A 的点射出,因此 e=n1+2n2 G B (4)由(2)(3) F C D n=n1+2n2+1 (5)由(4)-(1)可得 G n0=n2+1
《数据结构与算法》
★★★★★
第五章 二叉树
廊坊师范学院 数学与信息科学学院
树型结构--实例:五子棋
A
B
D
E
F
C
…...........
…...........
第五章 二叉树
本章重点难点
重点: 二叉树的定义,性质,存储结 构以及相关的应用——遍历,二叉搜 索树,堆优先 队列,Huffman树等 难点: 二叉树的遍历算法及相关应用
证明: 5.1 二叉树的概念
(1)总结点数为 ●二叉树的主要性质 n=n0+n1+n2 (2)除根结点外,每个 ●性质3: 结点都有一个边e进入 任何一棵二叉树,若其终端结点数为n0, n=e+1 度为2的结点数为n2,则n0=n2+1 (3)边e又是由度为1或2 A 的点射出,因此 e=n1+2n2 G B (4)由(2)(3) F C D n=n1+2n2+1 (5)由(4)-(1)可得 G n0=n2+1
A B C E D F G
证明: 由性质4可推出
由性质2(深度为k的 二叉树,至多有2k+1-1 个结点)可知,高度 为h(k+1)的二叉树,其 有n (n>0)个结点的完全二叉树的高度为 结点个数n满足: 「log2(n+1) ,深度为「log2(n+1) -1 2h-1-1<n<=2h-1 高度:二叉树中最大叶结点的层数+1 2h-1<n+1<=2h 取对数得到: 0层 1 h-1<log2(n+1)<=h 3 1层 2 因为h是整数,所以 h= log2(n+1) 5 2层 4
二叉树遍历

若二叉树非空,则依次执行下述操作: 1.后序遍历左子树; A 2.后序遍历右子树; B C 3.访问根结点。 其递归算法如下: D E F void postorder(BTREE *bt) { if (bt!=NULL) G { postorder(bt->lchild); H postorder(bt->rchild); printf(“%c”,bt->data); 后序遍历序列: DEBHGFCA } }
结点的层次(level)从根开始算起,根为第一层,根的 孩子为第二层,某结点所在的层从根结点往下计算。 在树的同一层上而双亲结点不同的结点互为堂兄弟。 树中结点的最大层数称为该树的深度或高度。
森林(forest)是m(m≥0)棵互不相交的树的集合,树和 森林的概念很密切,删去一棵树的根,就得到一个森 林。 G
2 4 8 9 10 5 6 3 7
性质6:对一棵有n个结点的完全二叉树的结点按层自左 向右编号,从编号为1的根结点开始到编号为 的结 点为止,都是有孩子结点的非叶子结点,余下的结点均是 叶子结点, 编号的结点可能只有左孩子结点,可 能是既左孩子结点又有右孩子结点。
1
2 4 8 9 10 5 6
#define DATATYPE2 char #define MAXSIZE 100 typedef struct { DATATYPE2 bt[MAXSIZE]; //下标为0的单元存放根节点 int btnum;//记录存储的节点数 } BTSEQ;
A B
root A ^
C
E
D
B
F
G
^
C ^
C
F
H
若二叉树非空,则依次执行下述操作: 1.中序遍历左子树; A 2.访问根结点; B C 3.中序遍历右子树。 其递归算法如下: D E F void inorder(BTREE *bt) G { if (bt!=NULL) { inorder(bt->lchild); H printf(“%c”,bt->data); inorder(bt->rchild); 中序遍历序列: DBEAGHFC } }
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《数据结构》第___5___次实验报告
班级:非师3班学号:100814320姓名:邹柱石日期:2011.11.9__成绩:_______ 实验题目:求二叉树中叶子结点的个数及二叉树的高度
一、实验目的
(1) 已知一棵二叉树,求该二叉树中叶子结点的个数及二叉树的高度。
(2) 进一步理解二叉链表存储结构
二、实验内容
(1)采用二叉链表作存储结构;
(2)设计递归算法求叶子结点的个数。
(3)设计非递归算法求叶子结点的个数。
(4)求二叉树的高度。
三、设计与编码
1、基本思想
求二叉树中叶子结点的个数,即求二叉树的所有结点中左、右子树均为空的结点个数之和。
因此可以将此问题转化为遍历问题,在遍历中“访问一个结点”时判断该结点是不是叶子,若是则将计数器累加。
算法如下:
求二叉树叶子结点个数算法
void CountLeaf(BiNode<T> *root, int &count)
//前序遍历根指针为root的二叉树以计算叶子数count,假定count的初值为0;
{
if (root!=NULL) {
if (root->lchild==NULL && root->rchild = =NULL)
count++; //若root所指的结点是叶子,则计数器加1;
CountLeaf(root->lchild, count); //累计左子树上的叶子数;
CountLeaf(root->rchild, count); //累计右子树上的叶子数;
}
}
非递归算法求叶子结点的个数可参考实验书P215。
求二叉树的高度可以在层序遍历函数中实现。
2、编码
#include<iostream>
int count=0;
using namespace std;
struct BiNode
{
char data;
BiNode *lchild,*rchild;
};
class BiTree
{
BiNode *root;
BiNode *Creat(BiNode *bt);
void Release(BiNode *bt);
void PreOder(BiNode *bt);
BiTreeDepth(BiNode *bt);
int CountLeaf(BiNode *bt);
public:
BiTree(){root=Creat(root);}
~BiTree(){Release(root);}
void PreOder(){PreOder(root);cout<<endl;}
BiTreeDepth(){BiTreeDepth(root);}
int CountLeaf(){CountLeaf(root);return count;}
};
BiNode *BiTree::Creat(BiNode *bt)
{
char ch;
cout<<"输入结点";
cin>>ch;
if(ch=='#')bt=NULL;
else{
bt=new BiNode;
bt->data=ch;
bt->lchild=Creat(bt->lchild);
bt->rchild=Creat(bt->rchild);
}
return bt;
}
void BiTree::Release(BiNode *bt)
{
if(bt!=NULL){
Release(bt->lchild);
Release(bt->rchild);
delete bt;
}
}
int BiTree::CountLeaf(BiNode *bt)
{
if (bt!=NULL)
{
if (bt->lchild==NULL && bt->rchild ==NULL) count++;
CountLeaf(bt->lchild);
CountLeaf(bt->rchild);
}
return count;
}
BiTree::BiTreeDepth(BiNode *bt)
{
if(bt==NULL)
return 0;
else
{
int dep1=BiTreeDepth(bt->lchild);
int dep2=BiTreeDepth(bt->rchild);
if(dep1>dep2)
return dep1+1;
else
return dep2+1;
}
}
void BiTree::PreOder(BiNode *bt)
{
if(bt==NULL)return;
else{
cout<<bt->data;
PreOder(bt->lchild);
PreOder(bt->rchild);
}
}
int main()
{
BiTree B;
B.BiTreeDepth();
cout<<"前序遍历";
B.PreOder();
cout<<"叶子结点个数:";
cout<<B.CountLeaf()<<endl;
cout<<"高度:";
cout<<B.BiTreeDepth()<<endl;
return 0;
}四、调试与运行
五、实验心得
深入掌握递归调用的妙处。