一、什么是树?
在前几篇的博文中主要讲述的是链式存储这种数据结构,它们的用途非常广泛,但是在实际的应用中,还存在着另一种非常重要的数据结构,它就是树。树的结构示意图如下所示:
上图就是一种数据结构----树,之所以在每个框中都留出空白,主要原因是这种结构如果根据上下文是能够传达一些重要的结构信息,比如我们可以作如下思考:
1、上图可以表示某公司的职能组织结构;
2、可以表示某公司从上层到底层的各种职位分布图;
3、可以表示某家族的族谱血缘关系;
4、可以表示计算机中的目录结构;
........
后面可以发挥自己的想象,只要能符合以上结构的都可以称之为树型结构。通过上述思考就可以发现树型结构的用途之广泛,它表示的是数据之间的一种层次关系,层与层之间存在着某种关系,我认为这就是树型结构的重要特点,这与其它结构有着很大的区别。
对树而言,先了解以下基本概念:
1
/ \
2 3
/ \ /
4 5 6
根结点:每棵树都有一个“根”,除非是一颗空树,称为root,通过root我们可以很容易的找到树上的各个支点,上图中“1”为树的root,称为根结点。
分支因子:一棵树上的每个节点,它们有可能有分支,有可能没有分支,分支的数目称为分支因子。如上图中,最大的分支因子为2,"3"结点的分支因子为1
孩子结点:父结点的分支的根节点
父结点:有分支的结点相对于分支的根节点来说是父结点
兄弟结点:有共同的父结点的结点
叶子结点: 没有子结点,如4\5\6结点。
分支结点:度大于0的结点
结点的度:树中某个结点的分支数称为该结点的度。
树的度:树的所有结点的度的最大值
m叉数:度为m的树
树的深度:叶子结点所在的最大层次
森林:m颗互不相交的树的集合。m>=0
树的逻辑表示方法:
1.树形
2.文氏图
3.凹入
4.括号 A(B(E,F),(C(G,J)))
二、什么是二叉树
对树而言,需要重点掌握二叉树。二叉树是一种特殊的顺序树,它规定有左右两个孩子,即左右孩子顺序不能替换,所以二叉树是一种有序树。二叉树的结点数为大于0小于等于2。对于二叉树,需要掌握以下性质:
性质1 在二叉树的第i层上至多有个结点(i>=1)
由数学归纳归纳法即可证明,
i=1,结点数为1
i=2,结点数为2
i=3,结点数为4
i=4,结点数为8
I=n, 结点数为.
性质2 深度为K的二叉树至多有-1个结点(k >=1)
换言之,如果二叉树的深度确定,则其最大的结点数也是确定的。
证明(可以利用性质1)
深度为K的二叉树的结点个数=二叉树中每一层结点个数的总和。即为:
= 1 + 2 + 4 + 8 + … + =-1(等比公式)
性质3 二叉树中,终端结点(叶子结点)个数与度为2的结点个数有如下关系:
= + 1
(注:度表示分支的个数,也指分支因子,终端结点也指叶子结点)
分析:二叉树中结点的度可以为0,1,2,也就是说需要证明结点的度为0与度为2的结点之间的关系是不变的。
证明:设二叉树中度为i的结点数为
则整棵二叉树的结点总数为:n =++ ------------(1)
除根结点外,每一个结点都是另一个结点的孩子,所以孩子数为n-1 --------(2)
度为i(I = 0,1,2)的结点,有i个孩子,
孩子数 = x 0 +x 1 +x 2 = 2 + ---------------(3)
因为:(3) = (2),所以,
n-1 = 2+ ------(4)
(4) – (1) ,得,
-1= - , 即 = + 1证毕.
或者可以从直观上来理解,每增加一个叶子结点,便会增加一个度为2的结点,而初始状态叶子结点的数目比度为2的结点多1个。
性质1、2、3是二叉树的通用特性。
在介绍其它性质之前,先了解另一种特殊的二叉树,即满二叉树,其定义如下:
满二叉树是指深度为K,且有-1个结点的二叉树。
特点:(1) 每层上结点数都达到最大
(2) 度为1的结点个数=0,即不存在分支数为1的结点
如下即为一棵满二叉树:(注意其顺序:结点层序编号方法,从根结点起从上至下逐层从左至右对二叉树的结点进行连续编号)
1
/ \
2 3
/ \ / \
4 5 6 7
当K = 3, 结点数-1 = 7
完全二叉树:深度为k,结点数为n的二叉树,当且仅当每个结点的编号都与相同深度的满二叉树中从1到n的结点一一对应时,称为完全二叉树。
根据定义可以理解:深度为k的完全二叉树,其结点总数比深度k-1的满二叉树要多,但一定比深度为k的满二叉树要少。即有:完全二叉树示意如下:
1
/ \
2 3
/ \
4 5 (注意编号顺序,与满二叉树一一对应)
性质4:结点数为n的完全二叉树,其深度为(向下取整)+ 1
由性质2及完全二叉树的定义有:
结点数满足:
性质5:在按层序编号的n个结点的完全二叉树中,任意一个结点i()有:
(1) i = 1时,结点i是树的根,否则(i> 1),结点i的双亲为i/2(向下取整),如
,取i = 2.
(2) 2i > n时,结点i无左孩子,为叶结点,否则结点i的左孩子为结点2i
(3) 2i+1 > n时,结点i无右孩子,否则结点i的右孩子为结点2i +1.
性质4与性质五是针对完全二叉树而言的。性质6是针对二叉树的链式存储结构而言。
性质6: 含有n个结点的二叉链表中,有n + 1个空链域。
二叉树的存储
1. 顺序存储结构
二叉树可以用一维数组或线性表来存储,而且如果这是完全二叉树,这种方法不会浪费空间。
并且这种紧凑排列,如果一个结点的索引为i,则它的子结点能在索引2i+1和2i+2找到,并且它的父节点(如果有)能在索引floor((i-1)/2)找到(假设根节点的索引为0)。
对于一般的二叉树,其层序编号不能反映出逻辑关系,但是可以将其按照完全二叉树编号,只不过把不存在的结点设置为NULL即可。但这么做有一个问题,就是会浪费存储空间。最坏情况下,一个深度为k的斜树(只有k个结点),却需要长度为2k-1的一维数组。所以顺序存储结构一般只用于完全二叉树。
2. 链式存储结构
每个结点含有一个数据域和两个指针域(分别指向左右子树)。
// 二叉树的二叉链表存储表示
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild,*rchild; // 左右孩子指针
}BiTNode,*BiTree;
利用这种结点结构所得的二叉树存储结构称之为二叉链表。在二叉链表中,如果想找到某个结点的双亲,需要从根节点开始遍历,所以有时为了便于找到结点的双亲,还可以在结点结构中增加一个指向其双亲结点的指针域,相应的二叉树存储结构称之为三叉链表。