一、树
1、定义
树是 N (N >= 0 )个结点的有限集合,N = 0 时,称为空树,这是一种特殊情况。在任意一棵非空树中应满足:
-
有且仅有一个特定的称为根的结点
-
树的根节点没有前驱节点
-
除根结点外的所有结点有且仅有一个前驱节点
-
树适合表示具有层次结构的数据
-
n个节点的树具有n-1条边
2、基本术语
树的结点:包含一个数据元素及若干指向子树的分支
结点的度:节点拥有的子树数(结点的孩子数目)
终端结点(叶子): 度为 0 的结点
非终端结点(分支结点):度不为 0 的结点
结点的层次:树中根结点的层次为 1,根结点子树的根为第 2 层,以此类推
树的度:树中所有结点度的最大值
树的深度:树中所有结点层次的最大值
孩子结点:结点的子树的根称为该结点的孩子
父结点:B 是 A 的孩子,则 A 是 B 的父亲
兄弟结点:同一双亲的孩子结点
堂兄弟结点:其父结点在同一层上的结点
祖先结点:从根到该结点所经分支上的所有结点
子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙。
有序树和无序树:在树中,如果各子树 Ti 是按照一定的次序从左向右安排的,且相对次序是不能随意改变的,则称为有序树,否则称为无序树。
森林:m(m≥0)棵互不相交的树的集合。将一棵非空树的根结点删去,树就变成一个森林;反之,给m 棵独立的树增加一个根结点,并把这 m 棵树作为该结点的子树,森林就变成一棵树。
3、树的性质
-
树定位节点树等于所有的度+1
-
度为m的树中第i层上至多有m*i-1个结点
-
高度为h的m叉树至多有(m*h-1)/(m-1)个结点
-
具有n个结点的m叉树的最小高度为logm(n(m-1)+1)
4、树的表示形式
(1)、倒悬树
(2)、嵌套集合的形式
(3)、广义表的形式
(A(B(EK,L),F),C(G(M,N)),D(H,I,J)
(4)、凹入表示法
使用栈将二叉树中的数据按照指定格式(兄弟间等长、(r)代表根节点、(0)代表左节点、(1)代表右节点)输出。
5、树的遍历
前序遍历:先遍历根节点,在遍历根的左孩子。直到某根节点没有左孩子在遍历其有孩子。
中序遍历:先遍历根节点的左孩子,直到没有左孩子在遍历根的右孩子,直到右孩子遍历完后再遍历根节点。
层序遍历:从第一层开始从上到下,每一层中从左到右一次进行遍历。
二、二叉树
1、定义
二叉树 是由 n(n>=0)个结点的有限集合构成,此集合或者为空集,或者由一个根结点及两棵互不相交的左右子树组成,并且左右子树都是二叉树。二叉树可以是空集合,根可以有空的左子树或空的右子树。二叉树不是树的特殊情况。二叉树结点的子树要区分左子树和右子树,即使只有一棵子树也要进行区分,说明它是左子树,还是右子树。这是二叉树与树的最主要的差别
2、五种形态
3、特点
-
每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点)
-
二叉树的子树有左右之分,其次不能颠倒
4、性质
-
在二叉树的第i层上至多有2^(i-1)个结点
-
深度为k的二叉树至多有2^(k)-1个结点
-
对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1
-
如果对一棵有n个结点的完全二叉树(其深度为[log2n]+1)的结点按层序编号(从第1层到第[log+1]层,每层从左至右),则对任一结点i(1<=i<=n)有:
-
如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲PARENT(i)是结点[i/2]
-
如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子LCHILD(i)是结点2i
三、特殊二叉树
1、满二叉树
深度为 k 且有 2k-1 个结点的二叉树。在满二叉树中,每层结点都是满的,即每层结点都具有最大结点数。满二叉树的顺序表示,即从二叉树的根开始, 层间从上到下, 层内从左到右,逐层进行编号(1,2, …, n)。
2、完全二叉树
深度为 k,结点数为 n 的二叉树,如果其结点 1~n 的位置序号分别与满二叉树的结点 1~n 的位置序号一一对应,则为完全二叉树
满二叉树必为完全二叉树, 而完全二叉树不一定是满二叉树。
完全二叉树中的某结点编号为 i,则:
-
若i=1;则i无双亲结点
若i>1;则i的双亲结点编号为 i/2
-
若2*i>n,则i无左孩子
若2*i<=n,则i右孩子结点编号为 2i+1
-
若2*i+1>n,则i无左孩子
若2*i+1<=n,则i右孩子结点编号为 2*i+1
3、二叉排序树
(1)、定义
二叉排序树又称二叉查找树,它或者是一个空树,或者是一个具有下列性质的二叉树:
-
若它的左子树不空,则左子树上所有节点的值均小于它的根结构的值
-
若它的右子树不空,则右子树上所有结点的值均大于它的根节点的值
-
它的左、右子树也分别是二叉排序树
(2)、性质
重要性质:中序遍历一颗二叉排序树时可以得到一个结点值递增的有序序列。
-
若它的左子树不为空,则左子树上的所有节点的值均小于根节点的值
-
若它的右子树不为空,则右子树上的所有结点的值均大于根节点的值
-
二叉排序树的左右子树也都是二叉排序树
4、二叉排序树基本操作
(1)、创建
算法思想:
-
将二叉排序树 T 初始化为空树。
-
读入一个关键字为 key 的结点。
-
如果读入的关键字 key 不是输入结束标志,则循环执行以下操作:
-
将此结点插入二叉排序树 T 中;
-
读入一个关键字为 key 的结点。
(2)、查找
算法思想:
-
若二叉排序树为空,则查找失败,返回空指针。
-
若二叉排序树非空,将给定值 key 与根结点的关键字 T->data.key 进行比较:
-
若 key 等于 T->data.key,则查找成功,返回根结点地址;
-
若 key 小于 T->data.key,则递归查找左子树;
-
若 key 大于 T->data.key,则递归查找右子树。
(3)、插入
算法思想:
-
若二叉排序树为空,则待插入结点 *S 作为根结点插入到空树中。
-
若二叉排序树非空,则将 key 与根结点的关键字 T->data.key 进行比较:
-
若 key 小于 T->data.key,则将 *S 插入左子树;
-
若 key 大于 T->data.key,则将 *S 插入右子树。
(4)、删除
算法思想:首先从二叉排序树的根结点开始查找关键字为 key 的待删结点,如果树中不存在此结点,则不做任何操作;否则,假设被删结点为 *p,其双亲结点为 *f,pl 和 pr 分别表示其左子树和右子树。
不失一般性,可设 *p 是 *f 的左孩子 ( 右孩子情况类似 )。下面分三种情况进行讨论。
-
若 *p 结点为叶子结点,即 pl 和 pr 均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
-
若 *p 结点只有左子树 pl 或者只有右子树 pr,此时只要令 pl 或 pr 直接成为其双亲结点 *f 的左子树即可。
-
若 *p 结点的左子树和右子树均不空,则删去 *p 之后令 *p 的直接前驱 *s 替代 *p,然后再从二叉排序树中删去其直接前驱 *s 即可。
5、平衡二叉树
定义:任意左右子树高度差的绝对值不超过1
三、二叉树的存储结构
1、顺序存储结构
仅适用于完全二叉树,用一组地址连续的存储单元依次自上而下、自左至右存储完全二上的结点元素,即将完全二叉树上编号为i的结点元素存储在如上定义的一维数组中下标为i-1的分量中
2、链式存储结构
二叉树的结点由一个数据元素和分别指向其左、右子树的两个分支构成,则表示二叉树的链表中的结点至少包含3个域:数据域data、左L、右指针域R。为了方便找到结点的双亲,则还可以在节点结构中增加一个指向其双亲结点的指针域,利用这两种结点结构所得的二叉树的存储结构分别称为二叉树链表和三叉链表
四、遍历二叉树
先中后遍历
先:ABDEHJIKCFG
中:DBHEJIKAFCG
后:DHJKIEBFGCA
1、遍历二叉树的递归操作
(时间复杂度O(n),空间复杂度O(n))
(1)、先序遍历二叉树
若二叉树为空,则空操作;否则:
-
访问根节点
-
先序遍历左子树
-
先序遍历右子树
(2)、中序遍历二叉树
若二叉树为空,则空操作;否则;
-
中序遍历左子树
-
访问根节点
-
中序遍历右子树
(3)、后序遍历二叉树
若二叉树为空,则空操作;否则;
-
后序遍历左子树
-
后序遍历右子树
-
访问根节点
2、树和森林的遍历
(1)、先序遍历森林
若森林为非空,则:
-
访问森林中第一棵树的根节点
-
先序遍历第一棵树中根结点的子树森林
-
先序遍历除去第一棵树之后剩余的树构成的森林
(2)、中序遍历森林
若森林为非空,则:
-
中序遍历森林中第一棵树的根节点的子树森林
-
访问第一棵树的根节点
-
中序遍历除去第一棵树之后剩余的树构成的森林