一、树的定义
树是n(n>=0)个结点的有限集。
n=0时称为空树。
在任意一颗非空树中:
1、有且仅有一个特定的称为根(root)的结点
2、当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、......、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree),如下图所示
树的定义其实就是我们在讲解栈时提到的递归的方法
对于树的定义还需要强调两点 (1)n>0时,根结点是唯一的,不可能存在多个根结点 (2)m>0时,子树的个数没有限制,但它们一定是互不相交的
1、结点分类
树的结点包含一个数据元素及若干个指向其子树的分支
度
结点拥有的子树数称为结点的度
叶结点
度为0的结点称为叶结点或终端结点
分支结点
度不为0的结点称为非终端结点或分支结点
树的度:
树内各结点的度的最大值
2、结点间关系
结点的子树的根称为该结点的孩子(child) 该结点称为孩子的双亲 同一个双亲的孩子之间互称兄弟 结点的祖先是从根到该结点所经分支上的所有结点
3、树的其他相关概念
结点的层次从根开始定义起,根为第一层,根的孩子为第二层
若某结点在第一层,则其子树的根就在第i+1层。 其双亲在同一层的结点互为堂兄弟
树中结点的最大层次称为树的深度或高度,当前树的深度为4![]()
如果将树种结点的各子树看成从左至右是有次序的,不能更换的,则称该树为有序树,否则称为无序树
森林是m(m>=0)课互不相交的树的集合 对树中每个结点而言,其子树的集合即为森林
二、树的抽象数据类型
ADT 树(Tree)
Data
树是由一个根结点和若干棵子树构成。树中结点具有相同的数据类型及层次关系。
Operation
InitTree(*T): 构造空树T。
DestroyTree(*T): 销毁树T。
CreateTree(*T, definition): 按definition中给出树的定义来构造树。
ClearTree(*T): 若树T存在,则将树T清为空树。
TreeEmpty(T): 若T为空树,返回true,否则返回false。
TreeDepth(T): 返回T的深度。
Root(T): 返回T的根结点。
Value(T, cur_e): cur_e是树T中一个结点,返回此结点的值。
Assign(T, cur_e, value): 给树T的结点cur_e赋值给value。
Parent(T, cur_e): 若cur_e是树T的非根结点,则返回它的双亲,否则返回空。
LeftChild(T, cur_e): 若cur_e是树T的非叶结点,则返回它的最左孩子,否则返回空。
RightSibling(T, cur_e): 若cur_e有右兄弟,则返回它的右兄弟,否则返回空。
InsertChild(*T, *p, i, c): 其中p指向树T的某个结点,i为所指结点p的度加上1,非空树c与T不相交,操作结果为插入c为树T中p所指结点的第i棵子树。
DeleteChild(*T, *p, i): 其中p指向树T的某个结点,i为所指结点p的度,操作结果为删除T中p所指结点的第i棵子树。
endADT
三、树的存储结构
1、双亲表示法
除了根结点外,其余每个结点不一定有孩子,但一定有且仅有一个双亲 用一组连续空间存储树的结点,同时在每个结点中,附设一个指示器指示其双亲结点在数组中的位置
结点结构如下:
(其中data是数据域,存储结点的数据信息;parent是指针域,存储该结点的双亲在数组中的下标)
(由于根结点没有双亲,我们可以将根结点的位置域设置为-1)
//树的双亲表示法结点结构定义
#define MAX_TREE_SIZE 100
typedef int TElemType;//树结点的数据类型,目前暂定为整型
typedef struct PTNode{//结点结构
TElemType data;//结点数据
int parent;//双亲位置
}PTNode;
typedef struct{//树结构
PTNode nodes[MAX_TREE_SIZE];//结点数组
int r, n;//跟的位置和结点数
}PTree;
这样的存储结构,我们可以根据结点的parent指针很容易找到它的双亲结点,所用的时间复杂度为0(1),直到parent为-1时,表示找到了树结点的根。
改进
如果需要访问结点的孩子,则需要遍历整个结构,不如增加一个最左边孩子的域,即长子域 (如果结点没有孩子,则将其长子域设置为-1)
四、二叉树的定义
二叉树是n(n>=)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成
4.1、二叉树的特点
- 每个结点最多有两棵子树,所以二叉树不存在度大于2的结点
- 左子树和右子树是有顺序的,次序不能任意颠倒
- 即使树中某结点只有一棵子树,也要区分它是左子树还是右子树
如果一棵二叉树由三个结点组成的话,那么这棵二叉树有几种形态呢?
4.2、特殊二叉树
1、斜树
所有结点都只有左子树的二叉树叫左斜树;所有结点都只有右子树的二叉树叫右斜树
左斜树跟右斜树统称为斜树。
它的特点就是每一层只有一个结点,结点的个数与二叉树的深度相同,类似线性表(线性表可以理解为树的一种极其特殊的表现形式)
2、满二叉树
如果二叉树每个分支结点都存在左右子树(叶子除外),叶子都在同一层,这种二叉树称为满二叉树。
满二叉树的特点
- 叶子只能出现在最下一层,出现在其他层就不可能达成平衡
- 非叶子结点的度一定是2
- 在同样深度的二叉树中,满二叉树的结点个数最多,叶子树最多
3、完成二叉树
对一棵具有n个结点的二叉树按层序编号,如果编号为i(1 ≤ i ≤ n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树
完全二叉树呢,其实是建立在满二叉树的基础上的,具体而言就是在满二叉树右下角的地方开始往左边依次砍n个结点后形成的即为完全二叉树!
在满二叉树右下角往左边依次砍掉1个结点后,就变成了完全二叉树
在满二叉树右下角往左边依次砍掉2个结点后,就变成了完全二叉树
当砍掉0个结点后,也是一棵完全二叉树,只是这时也是一棵满二叉树
记住几个关键点:满二叉树、右下角开始、依次往左
完全二叉树的特点
- 叶子结点只能出现在最下两层
- 最下层的叶子一定集中在左部连续位置
- 倒数二层,若有叶子结点,一定都在右部连续位置
- 如果结点度为1,则该结点只有左孩子,即不存在只有右树的情况
- 同样结点数的二叉树,完全二叉树的深度最小
4.3、二叉树的性质
- 在二叉树的第i层上至多有2 ^ (i - 1)个结点(i ≥ 1)
- 深度为k的二叉树至多有2 ^ k - 1个结点(k ≥ 1)
- 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2 + 1
- 具有n个结点的完全二叉树的深度为⌊log2n⌋ + 1(⌊x⌋表示不大于x的最大整数)
- 如果对一棵有n个结点的完全二叉树(其深度为⌊log2n⌋ + 1)的结点按层序编号(从第1层到第⌊log2n⌋ + 1层,每层从左到右),对任一结点i(1 ≤ i ≤ n)有:
- 如果i = 1,则结点i是二叉树的根,无双亲;如果i > 1,则其双亲是结点⌊i / 2⌋
- 如果2i > n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
- 如果2i + 1 > n,则结点i无右孩子;否则其右孩子是结点2i + 1
如果i = 1,则结点i是二叉树的根,无双亲;如果i > 1,则其双亲是结点⌊i / 2⌋
对于性质5的第一条来说,这是很显然的,因为i = 1时就是根结点。 i > 1时,比如结点5,那么它的双亲就是⌊i / 2⌋,也就是⌊5 / 2⌋ = 2, 结点9,它的双亲就是⌊i / 2⌋,也就是⌊9 / 2⌋ = 4
如果2i > n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
对于性质5的第二条来说,比如结点7,因为2 × 7 = 14超过结点总数10,所以结点7没有左孩子 同理,对于结点5,因为2 × 5 = 10等于结点总数10,所以它的左孩子是结点2i,也就是2 × 5 = 10结点
如果2i + 1 > n,则结点i无右孩子;否则其右孩子是结点2i + 1
对于性质5的第三条,比如结点5,因为2 × 5 + 1 = 11,大于结点总数10,所以它没有右孩子 同理,结点3,因为2 × 3 + 1 = 7,小于结点总数10,所以它的右孩子是结点7