该篇是关于树的概述,主要介绍什么是树、树的特点、树的表示方法、树的种类、树在存储结构中的表示、树/森林/二叉树之间的转换(原理)等,关于具体树(二叉树)的实现以及查找遍历等后续总结。
树的概述及特点
树是由n个(n>=0)结点组成的一个具有层次关系的集合。
如图,是一个普通的树的图像表示:
从这个图像中大致能看出为什么把这种层次关系的集合称为树了,这个就像一个倒着的树,树跟在上,树叶在下,中间是树干。
由 m(m >= 0) 个互不相交的树 组成的集合被称为森林。如上图,若以B、C为根节点的2棵子树就可以称为森林。
树的结点
树中的每个元素成为“结点”。
特殊的结点
- 根结点:没有父结点的结点。如上图的A。
- 叶子结点:没有子结点的结点,如上图的D、E、F、C都是叶子结点。
结点之间的特殊关系
- 父结点(或称为双亲结点):一个结点含有子结点,那么该结点称为其子结点的父结点。如上图,A是B、C的父结点。
- 子结点(或称为孩子结点):子结点和父结点是相对的。如上图,B、C就是A的子结点。
- 兄弟结点:具有相同的父结点称为兄弟结点。如上图,B、C即是兄弟结点,D、E、F也是兄弟结点。
树的特点
- 每个结点有0个或多个子结点。
- 非空树有且只有一个根结点。
- 非根结点有且只有一个父结点。
几个概念
- 结点的度:一个结点含有的子结点数,即结点的度。如上图,A结点的度为2,B结点的度为3。
- 树的度:一颗树中所有结点的度的最大值即树的度。如上图,树的度是3。
- 结点的层次:从根结点开始,根结点为第一层,根结点的子结点为第二层,依次类推。如上图,A为第一层,B、C为第二层,D、E、F为第三层。
- 树的高度(或树的深度):树中结点所在最大层次。如上图,树的高度即3。
树的表示方法
树的表示方法有很多,最常用的就是图像表示法。
这里就介绍两种比较常见的,图像表示法和符号表示法。
- 图像表示法
如最开始的图像表示(如上图)。各结点之间的关系很清晰。
- 符号表示法
用括号先将根结点放入一对圆括号中,然后把它的子树由左至右的顺序放入括号中,而对子树也采用同样的方法处理,同层子树之间用逗号隔开。上图用符号表示法表示为:(A(B(D,E,F),C))
树的种类
有序树与无序树
树中结点的子结点之间是否有顺序关系,即谁在左边、谁在右边是否有规定的。
这种,如果有规定 即子结点之间存在顺序关系,称为有序树。
相反,如果不存在顺序关系,则称为无序树。
二叉树
二叉树是非常重要的一种,后续很多都与之关联。
先看个示例图:
每个结点最多含有两个子树的树称为二叉树。 二叉树是有序树。
即各个结点的度不超过2。(也即直接的子结点数最多为2,上面讲的子结点、父结点基本都是直接的关系,不包含子结点的子结点或父结点的父结点)
二叉树的一些特性:
1.第i层,结点总数最多为:2i-1。
2.若树的深度为k,则二叉树结点总数最多为:2k-1。
3.叶子节点数n0 与 度为2的结点数n2 的关系:n0 =n2+1。
两种特殊二叉树
- 满二叉树
除叶子结点外,其他结点的度都是2(即只有两个子结点)的树 称为满二叉树。
满二叉树的一些特性:
1.满二叉树第i层,结点总数为:2i-1。
2.若树的深度为k,则满二叉树结点总数为:2k-1,叶子结点树为:2k-1。
3.满二叉树叶子节点都在对地层,不存在度为1的结点。
4.满二叉树,若有n个结点,则树的深度为:k=log2(n+1)。 2k-1=n
- 完全二叉树
假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树称之为完全二叉树。
即:如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。
完全二叉树的一些特性:
1.完全二叉树若结点总数为n,则树的深度为:⌊log2n⌋+1。
⌊ ⌋为取整,如⌊log26⌋+1=3
2.假如完全二叉树中结点编号从上到下,从左到右依次从1到n。则有:
如果i>1时,父结点为⌊i/2⌋。(i=1即根结点,无父结点)。
如果2i>n, 则i无左孩子(为叶子结点);否则i的左孩子是2i。
如果2i+1>n, 则i无右孩子;否则i右孩子是2i+1.
- 平衡二叉树(AVL树)
当且仅当任何节点的两棵子树的高度差不大于1的二叉树
树在存储结构中的表示
树在存储结构中的表示,主要有3种:双亲表示法、孩子表示法、孩子兄弟表示法。
双亲表示法
双亲表示法,采用数组的存储方式。
每个结点包含两个部分:数据部分和指向父结点(双亲结点)的指针。
数组元素定义:
data | parent |
---|---|
结点信息 | 结点的双亲结点在数组中下标 |
如下,表示数组中元素的定义。
ArrNode[] treeArr = new ArrNode[TREE_SIZE];
class ArrNode {
//数据部分
Object data;
//双亲结点位置
int parent;
}
根结点没有父结点,所以第二个部分存储为 -1。
示例:一颗普通树 用双亲表示法,存储示意图
双亲表示法中,结点很容易找到父结点。但如果要找孩子结点,则需要遍历后才能找到。
孩子表示法
孩子表示法,采用数组+单链表的存储方式。
数组部分存储了结点的值,以及指向第一个孩子结点的指针。单链表存储的是某个结点的所有孩子结点,从左到右。所以N个结点,即数组大小为N,有N个链表。
如下,表示数组中元素定义,以及链表中元素定义。
数组元素定义:
data | firstChildNode |
---|---|
结点信息 | 指向第一个孩子结点指针 |
链表中元素定义:
child | next |
---|---|
孩子结点在数组中的下标 | 指向下个孩子结点的指针 |
ArrNode[] treeArr = new ArrNode[TREE_SIZE];
//链表中存储的孩子结点定义
class ChildNode {
//孩子结点对应的在数组中存储的下标值
int child;
//下个孩子结点
ChildNode next;
}
//数组中存储元素定义
class ArrNode {
//数据部分
Object data;
//指向第一个孩子结点指针(引用)
ChildNode firstChildNode;
}
如果是叶子结点(即没有孩子结点),链表为空。
示例:一颗普通树 用孩子表示法,存储示意图
孩子表示法中,结点很容易找到孩子结点。但如果要找双亲结点,则需要遍历后才能找到。
提示:双亲结点和孩子结点都有明显的缺陷,但我们也可以将他们结合起来。即在孩子表示法基础上,数组元素定义中增加双亲位置的指针(即双亲表示法中的parent定义)。这种被称作“双亲孩子表示法”
数组元素定义:
data | parent | firstChildNode |
---|---|---|
结点信息 | 结点的双亲结点在数组中下标 | 指向第一个孩子结点指针 |
链表中元素定义:
child | next |
---|---|
孩子结点在数组中的下标 | 指向下个孩子结点的指针 |
孩子兄弟表示法
孩子兄弟表示法,采用链表的存储方式。
通过孩子结点和兄弟结点来表示。
data | firstChild | firstBrother |
---|---|---|
结点信息 | 第一个孩子结点的指针(左孩子) | 第一个兄弟结点的指针(右兄弟) |
//结点定义
class TreeNode {
Object data;
TreeNode firstChild;
TreeNode firstBrother;
}
示例:一颗普通树 用孩子兄弟表示法,存储示意图
树、森林与二叉树之间的转换
上面的孩子兄弟表示法也能感受到,那就是普通树转换成了一个二叉树。
网上有很多关于树、森林与二叉树之间的转换。这里简单总结下。
---若有不对,请指出。
树、森林转换成二叉树
结合上面孩子兄弟表示方法理解。
其实树 或者 森林 转换成二叉树是一样的。 因为树就是一个森林,单树森林。
转换规则简单是:
森林中第一颗树的根结点 作为 二叉树的根结点。然后所有结点 依次 遵循左孩子有兄弟即可。
下面简单示意说明下。
树(单树森林)转换二叉树
//单树 二叉树
A A
/ | /
B C D =======> B
| /| /
E F G H E C
D
/
F
G
H
二叉树根结点即A(第一个棵树根结点),A的左孩子为B,右孩子为null(A是第一个树根结点,无兄弟)。然后看B,左孩子为E,右孩子为C(B、C、D兄弟结点)。再看E、C,依次类推即可将树转换成二叉树。
森林转换二叉树
同树转换成二叉树一样,将森林中的树看成兄弟即可。
// 森林 二叉树
A
/
A E G /
/ | | / B E
B C D F H I =======> /
| C F G
J /
D H
/
J I
二叉树根结点即A(第一个棵树根结点),A的左孩子为B,右孩子为E(森林中的所有树看作兄弟结点)。然后看B,左孩子为null,右孩子为C(B、C、D兄弟结点),再看E,左孩子为F,右孩子为G。依次类推即可将森林转换成二叉树。
二叉树转换成树、森林
二叉树 转换成 树 或者 森林 也是一样的。 是上面树、森林转换成二叉树的逆向过程。
转换规则简单是:
二叉树的根结点即第一颗树的根结点。然后二叉树所有结点的 左孩子为(树或森林)结点的第一个孩子结点,右孩子为结点的兄弟结点。
下面简单示意说明下。
二叉树转换树(单树森林)
//二叉树 单树
A
/
B
/ A
E C / |
=======> B C D
D | /|
/ E F G H
F
G
H
二叉树中A,有左孩子无右孩子。所以,该二叉树对应的是一棵树。A即树的根结点,左孩子B(二叉树中)即A的孩子结点(单树中)。看E、C(二叉树中),E为B左孩子,即E为B的孩子结点(孩子结点),C为B右孩子,即C为B的兄弟结点。依次类推即可。
二叉树转换森林
同理
// 二叉树 森林
A
/ A E G
/ / | | /
B E =======> B C D F H I
/ |
C F G J
/
D H
/
J I
二叉树中A,有左孩子有右孩子。所以,该二叉树对应的不是一颗树。A即第一颗树的根结点,左孩子B(二叉树中)即A的孩子结点(第一颗树中);右孩子E(二叉树中)是A的兄弟,A是第一颗树的根结点,所以E为第二颗树根结点。看B的左右孩子(二叉树中),左孩子为空即B(第一颗树中)没有孩子结点,右孩子为C即是B的兄弟结点 在第一颗树中。依次类推即可。