1、树的概念
树形结构是结点间有分支的、层次的结构,它是一种常见的又很重要的非线性结构。下面首先给出树形结构的递归定义。
定义 树(tree)是n(n>=0)个结点的有限集合T,如果T为空,则它是一棵空树(null tree),否则
(1)T中有一个特别标出的称为根(root)的结点;
(2)除根结点之外,T中其余结点被分成m个(m>=0)互不相交的非空集合T1,T2,...,Tm,其中每个集合本身又都是树。树T1,T2,...,Tm称为T之根的子树。
一些基本术语:
.结点的度数(degree) 树中结点子树的个数。
.树叶(leaf) 没有子树的结点称为树叶或终端结点。
.分支结点(branch node) 非终端结点。
.子女(child)或儿子(son) 一个结点的子树的结点是该结点的子女(或儿子)。
.父母(parent) 若结点s是结点p的儿子,则称p是s的父母或父亲。
.兄弟(sibling) 有相同父母结点的结点互为兄弟。
.子孙(descendent) 根为r的树(或子树)中所有结点都是r的子孙。除r之外,它们又都是r的真子孙(proper descendent)。
.祖先(ancestor) 从根r到结点p的路径(有且仅有一条这样的路径)上的所有结点都是p之祖先。除p之外,它们又都是p的真祖先(proper ancestor)。
.有序树(ordered tree) 树中各结点的儿子都是有序的。
.层数(level) 定义树根的层数为1,其他结点的层数等于其父母结点的层数加1。
.高度(或深度)(height) 树中结点的最大层数,规定空树的高度为0。
.树林(或森林)(forest) n(n>=0)个互不相关的树的集合。
2、二叉树
二叉树是树形结构的另一个重要类型。二叉树的每个结点至多有两个子女,而且子女有左、右之分。二叉树的存储结构简单,存储效率较高,树运算的算法实现也相对简单。二叉树还可用来表示树(树林),二叉树在数据结构中有着重要的地位。
定义 (二叉树的递归定义) 二叉树由结点的有限集合构成,这个有限集合或者为空集,或者由一个根结点及两棵不相交的分别称作这个根的左子树和右子树的二叉树组成。
定义 一棵深度为h且有2的k次方减1个结点的二叉树称为满二叉树。
定义 深度为h且有n个结点的二叉树,当且仅当其每一个结点都与深度为h的满二叉树中编号1~n的结点一一对应时,称为完全二叉树。
二叉树的性质
性质1任何一棵含有n(n>0)个结点的二叉树恰有n-1条边。
性质2深度为h的二叉树至多有2h-1个结点(h≥0)。
性质3设二叉树的结点个数为n,深度为h,则
性质4如果对一棵有n个结点的完全二叉树的结点,按层次次序编号(每层从左至右),则对任一结点i(1≤i≤n),下述结论成立:
(1)若i=1,则结点i为二叉树的根结点;若i>1,则结点[]为其父母结点。
(2)若2I>n,则结点i无左子女;否则,结点2i为结点i左子女。
(3)若2I+1>n,则结点i无右子女;否则,结点2I+1为其右子女。
二叉树的存储方式
.顺序存储
(1)完全二叉树的顺序存储
(2)非完全二叉树的顺序存储
.链接存储
(1)Leftchild-Rightchild表示法
(2)三重链表示
树(树林)与二叉树的相互转换
定义 定义树林F=(T1,T2,...,Tn)到二叉树B(F)的转换为:
- 若n=0,则B(F)为空的二叉树。
- 若n>0,则B(F)的根是T1的根W1,B(F)的左子树是B(T11,T12,...,T1m),其中T11、T12、...、T1m是W1的子树;B(F)的右子树是B(T2,...,Tn)。
定义 设B是一棵二叉树,r是B的根,L是r的左子树,R是r的右子树,则对应于B的树林F(B)的定义为:
(1) 若B为空,则F(B)是空的树林。
(2) 若B不为空,则F(B)是一棵树T1加上树林F(R),其中树T1的根为r,r的子树为F(L)。
3、树(树林)、二叉树的遍历
树(树林)的遍历
树(树林)的遍历可以按宽度方向和深度方向实现。遍历是树形结构的一种很重要的运算,遍历一棵树(或一片树林)就是按一定的次序系统地访问树(树林)的所有结点。
.按宽度方向遍历
首先依次访问层数为1的结点,然后访问层数为2的结点,直到访问完最底层的所有结点。
.按深度方向遍历
(1)先根次序(先根后子女)
.访问一棵树的根。
.在先根次序下遍历头一棵树树根的子树。
.在先根次序下遍历其他的树。
(2)后根次序(先子女后根)
.在后根次序下遍历头一棵树树根的子树。
.访问头一棵树的根。
.在后根次序下遍历其他的树。
二叉树的遍历
考虑到二叉树是由三个基本单元组成:根结点、左子树和右子树,若以L,N,R分别表示遍历左子树、访问根结点和遍历右子树,则有NLR、LNR、LRN、NRL、RNL、RLN六种遍历方式,且前三种遍历方式与后三种遍历方式是对称的。若规定先左后右的次序,则只有下面三种二叉树的遍历方式。
(1)前序法(NLR次序),递归定义为:
.访问根结点;
.按前序遍历左子树;
.按前序遍历右子树。
(2)后序法(LRN次序),递归定义为:
.按后序遍历左子树。
.按后序遍历右子树。
.访问根。
(3)对称序(中序、LNR次序),递归定义为:
.按对称序遍历左子树;
.访问根;
.按对称序遍历右子树。
任何一棵树(树林)的先根次序正好与对应的二叉树的前序序列对应,后根次序正好与对应二叉树的对称序序列对应。
4、抽象数据类型BinaryTree以及类BinaryTree
抽象数据类型BinaryTree
定义 ADT BinaryTree为:
数据 指向二叉树树根的指针root。
结构 LeftChild-RightChild表示。
操作
BinaryTree()--初始化操作,置空树。
IsEmpty()--判断二叉树是否为空,若二叉树非空,则返回FALSE,否则返回TRUE。
Root(x)--求根结点的函数。
MakeTree(element,left,right)--构造二叉树,其根结点为element,左子树根结点的指针为left,右子树根结点的指针为right。
PreOrder(root)--按次序遍历以root为根的二叉树。
InOrder(root)--按对称遍历以root为根的二叉树。
PostOrder(root)--按后序遍历以root为根的二叉树。
5、二叉树的遍历算法
非递归(使用栈)的遍历算法
栈是实现递归最常用的结构,对于用递归方式定义的二叉树,最自然的实现遍历运算的方式是使用一个栈来记录尚待遍历的结点或子树信息(保存子树的信息只需保存子树根结点的信息),以便以后遍历。
线索化二叉树的遍历