第6章树与二叉树Word文档下载推荐.docx
- 文档编号:19179140
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:35
- 大小:221.85KB
第6章树与二叉树Word文档下载推荐.docx
《第6章树与二叉树Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《第6章树与二叉树Word文档下载推荐.docx(35页珍藏版)》请在冰豆网上搜索。
通常所说的树指的是无序树。
若干棵互不相交的树的集合称为森林(forest)。
给森林加上一个根结点就变成一棵树,将树的根结点删除就变成由子树组成的森林。
树结构可以用如图6.2所示的树图表示,这种图示法比较直观,但有时显得不方便。
也可以用广义表的形式表示树结构。
例如,图6.2(b)所示树的广义表表示形式为:
A(B(C,D),E(F,G,H),I(J))。
表示树结构的广义表没有共享和递归成分,是一种纯表。
广义表中的原子对应于树的叶结点,树的非叶结点则用子表表示。
6.1.2树的基本术语
家谱可以用树来描述,反之,与树有关的一些基本术语也常用家族成员关系来说明。
1.结点(node)
结点表示树集合中的一个数据元素,它由元素的数据和指向它的子结点的指针构成。
例如,图6.2(a)表示一棵仅有1个结点的树,图6.2(b)表示一棵具有10个结点的树。
2.子结点与父结点(childnode与parentnode)
若结点N有子树,则子树的根结点称为N的子结点,又称孩子或子女结点。
与子结点对应,N称为其子结点的父结点,又称父母或双亲结点。
在一棵树中,根没有父结点。
例如在图6.2(b),结点B、E、I是结点A的子树的根,所以结点A的子女是结点B、E、I,结点A是这些结点的父结点。
A作为整个树的根结点,它没有父结点。
3.兄弟结点(siblingnode)
同一个父结点的子结点之间是兄弟关系,它们互称为兄弟结点。
例如,B、E、I是兄弟,C和D也是兄弟,但F和C不是兄弟。
4.祖先结点与后代结点(ancestornode与descendantnode)
树中从根结点到某结点N所经过的所有结点,称作结点N的祖先结点。
N的所有子结点,以及子结点的子结点构成结点N的后代结点。
例如,B和A是C的祖先结点,H则是A的后代结点。
5.结点的度和树的度(degree)
结点的度定义为结点所拥有子树的棵数,而树的度是指树中各结点度的最大值。
例如图6.2(b)中,A的度是3,B的度是2,C和D的度都是0,整个树的度为3。
6.叶子结点与分支结点(leafnode与branchednode)
度为0的结点称为叶子结点,又称为终端结点。
除叶子结点以外的其他结点称为分支结点,又称为非叶子结点或非终端结点。
例如,C和D是叶子结点,B、E和I是非叶子结点。
7.边(edge)
如果结点M是结点N的父结点,用一条线将这两个结点连接起来就构成树的一条分支,它称为连接这两个结点的边,该边可以用有序对<
M,N>
表示。
例如,<
A,B>
和<
B,C>
都是树的边。
8.路径与路径长度(path与pathlength)
如果(N1,N2,…,Nk)是由树中结点组成的一个序列,且<
Ni,Ni+1>
(1≤i≤k-1)都是树的边,则该序列称为从N1到Nk的一条路径。
路径上边的条数称为该路径的长度。
例如,从A到C的路径是(A,B,C),该路径的长度为2。
9.结点的层次(level)和树的深度(depth)
结点N的层次与从根结点到该结点的路径长度有关,如果根结点的层次定义为0,它的子结点的层次则为1,亦即,某结点的层次等于它的父结点的层次加1,兄弟结点的层次相同。
树中结点的最大层次数称为树的深度(depth)或高度(height)。
例如在图6.2(b)中,A的层次为0,B的层次为1,C的层次为2。
C、F虽不是兄弟结点,但它们的层次相同,称为同一层上的结点;
该树的深度为2。
6.2二叉树的定义与实现
6.2.1二叉树的定义
二叉树(binarytree)也可以用递归形式来定义,它是由n(n≥0)个结点组成的有限集合。
结点个数为零,即n=0时称为空二叉树;
0时,二叉树由一个根结点和两棵互不相交的子二叉树构成,子二叉树从左至右是有次序的,分别称为左子树和右子树。
从定义中可以看出,二叉树是一种特殊的树,树中定义的有关术语,如度、层次等,大都适用于二叉树。
二叉树的结点最多只有两棵子树,所以二叉树的度最大为2。
但是,即使二叉树的度为2,它与度为2的树的结构也是不等价的,它们的区别在于:
二叉树是一种有序树,因为二叉树中每个结点的两棵子树有左、右之分,即使只有一个子树,也要区分是左子树还是右子树,而普通的树指的是无序树。
例如图6.3中的两棵树,如果看成是一般的树结构,则图(a)和图(b)表示同一棵树;
如果看成是二叉树结构,则图(a)和图(b)表示两棵不同的二叉树。
图6.3不同的二叉树与相同的度为2的树
由上述定义可知,二叉树有五种基本形态,如图6.4所示。
(a)为空二叉树。
(b)为只有一个结点(根结点)的二叉树。
(c)为由根结点,非空的左子树和空的右子树组成的二叉树。
(d)为由根结点,空的左子树和非空的右子树组成的二叉树。
(e)为由根结点,非空的左子树和非空的右子树组成的二叉树。
其中,图6.4(c)和(d)是两种不同形态的二叉树。
图6.4二叉树的基本形态
【例6.1】画出3个结点的树与二叉树的基本形态。
3个结点的树可以有如图6.5(a)所示的2种基本形态;
3个结点的二叉树可以有如图6.5(b)所示的5种基本形态。
图6.53个结点的树与二叉树的基本形态
6.2.2二叉树的性质
性质一:
二叉树第i层的结点数目最多为2i(i≥0)。
这里,根结点的层次定义为0。
用归纳法容易证明这条性质。
i=0时,根结点是0层上的惟一结点,故该层结点数为2i=20=1,命题成立。
假设命题对i-1(i≥1)层成立,即第i-1层上的最大结点数为2i-1。
归纳推理:
根据假设,第i-1层上的最大结点数为2i-1;
由于二叉树中每个结点的度最大为2,故第i层上的最大结点数为2×
2i-1=2i。
命题成立。
性质二:
在深度为k的二叉树中,最多有2k+1-1个结点(k≥0)。
由性质一可知,在深度为k的二叉树中,最大结点数为
。
性质三:
二叉树中,若叶子结点数为n0,2度结点数为n2,则有n0=n2+1。
设二叉树的总结点数为n,度为1的结点数为n1,则有
n=n0+n1+n2
因为度为1的结点有1个子女,度为2的结点有2个子女,叶子结点没有子女,根结点不是任何结点的子女,所以从子女结点数的角度看,有
n=0×
n0+1×
n1+2×
n2+1
综合上述两式,可得n0=n2+1,即二叉树中叶子结点数比度为2的结点数多1。
性质四:
如果一棵完全二叉树有n个结点,则其深度
每一层的结点数目都达到最大值的二叉树称为满二叉树(fullbinarytree)。
从定义可知,一棵深度为k的满二叉树具有2k+1-1(k≥0)个结点。
对满二叉树的结点进行连续编号,约定编号从根结点开始,自上而下,每层自左至右,如图6.6(a)所示。
一棵具有n个结点、深度为k的二叉树,如果它的每个结点都与深度为k的满二叉树中编号为0~n-1的结点一一对应,则称这棵二叉树为完全二叉树(completebinarytree),如图6.6(b)所示。
由定义可知,完全二叉树具有下列特点:
●满二叉树一定是完全二叉树,而完全二叉树不一定是满二叉树,它是具有满二叉树结构的而不一定满的二叉树。
完全二叉树只有最下面一层可以不满,其上各层都可看成满二叉树。
●完全二叉树至多只有最下面两层结点的度可以小于2。
●完全二叉树最下面一层的结点都集中在该层最左边的若干位置上,图6.6(c)不是一棵完全二叉树。
图6.6满二叉树与完全二叉树
性质五:
若将一棵具有n个结点的完全二叉树按顺序表示,对于编号为i(0≤i≤n-1)的结点,有如下特点:
●若i=0,则结点i为根结点,无双亲;
若i≠0,则结点i的双亲是编号为(i-1)/2的结点。
●若2i+1≤n-1,则结点i的左孩子是编号为2i+1的结点;
若2i+1>n-1,则结点i无左孩子。
●若2i+2≤n-1,则结点i的右孩子是编号为2i+2的结点;
若2i+2>
n-1,则结点i无右孩子。
6.2.3二叉树的存储结构
二叉树的存储结构有顺序存储结构和链式存储结构两种。
二叉树结构是一种具有层次关系的数据结构,用链式存储结构实现二叉树更加灵活方便,所以一般情况下,采用链式存储来实现二叉树结构。
1.二叉树的顺序存储结构
二叉树的顺序存储结构适用于完全二叉树,对完全二叉树的结点进行顺序编号,将编号为i的结点存放在数组中下标为i的单元上。
顺序存储完全二叉树时,根据二叉树的性质五,通过计算可以直接得到父结点、左子结点和右子结点的位置。
在图6.7中,一个完全二叉树的所有结点按顺序存放在一个数组中。
图6.7顺序存储结构的完全二叉树
2.二叉树的链式存储结构
为了以链式存储结构实现二叉树,在逻辑上,二叉树的结点应有3个域:
●数据域data,表示结点的数据元素;
●左链域left,指向该结点的左子结点;
●右链域right,指向该结点的右子结点。
图6.8二叉树的链式存储结构
二叉树本身则用其根结点root表示。
树中某结点的左子结点也代表该结点的左子二叉树,同理,该结点的右子结点代表它的右子二叉树。
若二叉树为空,则root==null。
若结点的左子树为空,则其left链为空值,即left==null;
若结点的右子树为空,则其right链为空值,即right==null。
图6.8显示了一颗二叉树的链式存储结构。
6.2.4二叉树类的定义
1.二叉树的结点类
将链式存储结构的二叉树的结点声明为BinaryTreeNode<
T>
泛型类,其中有3个成员变量:
data用于表示数据元素,left和right分别是指向左、右孩子结点的链。
3个成员变量都是私有的,不能被其他类直接访问。
我们通过添加相应的公有属性Data,Left和Right访问这些域成员。
构造方法将创建一个有值的结点。
.NETFramework和C#语言2.0版开始增加了泛型,泛型利用类型参数将一个或多个类型的指定推迟到声明并实例化该类对象或调用方法的时候。
使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能,泛型最常见的用途是创建集合类。
publicclassBinaryTreeNode<
{
privateTdata;
//数据元素
privateBinaryTreeNode<
left,right;
//指向左、右孩子结点的链
publicBinaryTreeNode(){
left=right=null;
}
//构造有值结点
publicBinaryTreeNode(Td){
data=d;
left=right=null;
publicTData{
get{returndata;
}
set{data=value;
publicBinaryTreeNode<
Left{
get{returnleft;
set{left=value;
Right{
get{returnright;
set{right=value;
}
2.二叉树类
声明BinaryTree类表示链式存储结构的二叉树,其中成员变量root指向二叉树的根结点。
publicclassBinaryTree<
protectedBinaryTreeNode<
root;
//指向二叉树的根结点
publicBinaryTree(){//构造空二叉树
root=null;
6.3二叉树的遍历
6.3.1二叉树遍历的概念
二叉树的遍历(traversal)就是按照一定规则和次序访问二叉树中的所有结点,并且每个结点仅被访问一次,这样一次完整的遍历就按照指定的规则对二叉树中的结点产生一种线性次序的序列。
所谓访问一个结点,可以是对该结点的数据元素进行查阅、修改等操作。
二叉树的遍历过程,可以按层次进行,即从根结点开始,逐层深入,同层从左至右依次访问结点。
二叉树是由根结点、左子树和右子树三个部分组成的,依次遍历这三个部分,便是遍历整个二叉树。
若规定对子树的访问按“先左后右”的次序进行,则遍历二叉树有3种次序:
●先根次序:
访问根结点,遍历左子树,遍历右子树。
●中根次序:
遍历左子树,访问根结点,遍历右子树。
●后根次序:
遍历左子树,遍历右子树,访问根结点。
图6.9中显示了对二叉树进行3种不同次序遍历所产生的序列。
以先根次序遍历二叉树为例,遍历过程如下:
若二叉树为空,则空操作,返回;
否则从根结点开始,
1)访问当前结点。
2)若当前结点的左子树不空,则沿着left链进入该结点的左子树。
3)若当前结点的右子树不空,则沿着right链进入该结点的右子树。
图6.9二叉树的遍历
依据二叉树的遍历规则,可以知道:
根结点处在先根序列的第一个,因为它是最先被访问的;
而在后根次序遍历中,根结点是最后被访问的,所以根结点处在后根序列的最后一个;
在中根序列中,左子树上的结点都排在根结点前面,其右子树上的结点都排在根结点后面。
所以,先根次序或后根次序反映双亲与孩子结点的层次关系,中根次序反映兄弟结点间的左右次序。
6.3.2二叉树遍历的递归算法
1.先根次序遍历二叉树的递归算法
按先根次序遍历二叉树的递归算法如下:
2)按先根次序遍历当前结点的左子树。
3)按先根次序遍历当前结点的右子树。
在二叉树结点类BinaryTreeNode中,增加按先根次序遍历以某结点为根的二叉树的递归方法。
ShowPreOrder方法在控制台显示二叉树结点的值,而TraversalPreOrder方法更一般化,它将各结点的值按指定的次序存放在线性表,其参数sql可以是数组或线性表List类型。
//输出本结点为根结点的二叉树,先根次序
publicvoidShowPreOrder(){
Console.Write(this.Data+"
"
);
BinaryTreeNode<
q=this.Left;
if(q!
=null)
q.ShowPreOrder();
q=this.Right;
//先根次序遍历以本结点为根结点的二叉树,将各结点的值存放在表sql中
publicvoidTraversalPreOrder(IList<
sql){
sql.Add(this.Data);
q.TraversalPreOrder(sql);
2.中根次序遍历二叉树的递归算法
按中根次序遍历二叉树的递归算法如下:
1)按中根次序遍历当前结点的左子树。
2)访问当前结点。
3)按中根次序遍历当前结点的右子树。
在二叉树结点类BinaryTreeNode中,增加按中根次序遍历以某结点为根的二叉树的递归方法。
publicvoidShowInOrder(){
q.ShowInOrder();
publicvoidTraversalInOrder(IList<
q.TraversalInOrder(sql);
3.按后根次序遍历二叉树的递归算法
按后根次序遍历二叉树的递归算法如下:
1)按后根次序遍历当前结点的左子树。
2)按后根次序遍历当前结点的右子树。
3)访问当前结点。
在二叉树结点类BinaryTreeNode中,增加按后根次序遍历以某结点为根的二叉树的递归方法。
publicvoidShowPostOrder(){
q.ShowPostOrder();
publicvoidTraversalPostOrder(IList<
q.TraversalPostOrder(sql);
4.从根结点遍历整个二叉树
在二叉树类BinaryTree中,增加如下的6个方法,每一对Show/Traversal方法,分别调用二叉树结点类BinaryTreeNode中实现的按相应次序遍历二叉树的递归方法,遍历从根结点开始的整个二叉树。
//先根次序遍历二叉树
publicvoidShowPreOrder(){
Console.Write("
先根次序:
if(root!
root.ShowPreOrder();
Console.WriteLine();
publicList<
TraversalPreOrder(){
List<
sql=newList<
();
root.TraversalPreOrder(sql);
returnsql;
//中根次序遍历二叉树
publicvoidShowInOrder(){
中根次序:
root.ShowInOrder();
TraversalInOrder(){
root.TraversalInOrder(sql);
//后根次序遍历二叉树
publicvoidShowPostOrder(){
后根次序:
root.ShowPostOrder();
TraversalPostOrder(){
root.TraversalPostOrder(sql);
【例6.2】按先根、中根和后根次序遍历二叉树。
程序BinaryTreeTest.cs调用BinaryTree类,先建立如图6.9所示的二叉树,然后以先根、中根和后根次序遍历二叉树。
程序还演示了BinaryTree类的泛型能力,即在二叉树实例化时决定结点数据的类型。
classBinaryTreeTest{
staticvoidMain(string[]args){
BinaryTree<
int>
btree=newBina
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 二叉