每日学习录(数据结构—树)(上)

目录

六、树

6.1 树的定义

​编辑6.1.1 结点分类

6.1.2 结点间的关系

6.1.3 树的其他相关概念

6.2 树的抽象数据类型

6.3 树的存储结构

6.3.1 双亲表示法

6.3.2 孩子表示法

6.3.3 孩子兄弟表现法

6.4 二叉树的定义

6.4.1 二叉树特点

6.4.2 特殊的二叉树

 斜树

满二叉树

完全二叉树

6.5 二叉树的性质


六、树

6.1 树的定义

树(Tree)是 n(n≥0)个结点的有限集。n=0时称为空树。在任意一棵非空树中:(1) 有且仅有一个特定的称为根(Root)的结点;(2) 当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、······、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。

如图:

6.1.1 结点分类

树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶结点(Leaf)或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点树的度是树内各结点的度的最大值。如图,因为这棵树结点的度的最大值是结点D的度,为3,所以树的度也为3。

6.1.2 结点间的关系

结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(对于结点来说其父母同体,唯一的一个,所以只能把它称为双亲)。同一个双亲的孩子之间互称兄弟(Sibling)。结点的祖先是从根到该结点所经分支上的所有结点。所以对于H来说,D、B、A都是它的祖先。反之,以某结点为根的子树中的任一结点都称为该结点的子孙。B的子孙有D、G、H、I,如图。

6.1.3 树的其他相关概念

结点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层。若某结点在第L层,则其子树的根就在第L+1层。其双亲在同一层的结点互为堂兄弟。显然下图中的D、E、F是堂兄弟,而G、H、I与J也是堂兄弟。树中结点的最大层次称为树的深度(Depth)或高度,下图的树的深度为4。

如果将树中结点的各子树看成从左至右是有次序的,不能互换的,则称该树为有序树,否则称为无序树。

森林(Forest)是m(m≥0)棵互不相交的树的集合。==对树中每个结点而言,其子树的集合即为森林。

对比线性表的结构,他没有很大的不同:

6.2 树的抽象数据类型

6.3 树的存储结构

树中某个结点的孩子可以有多个,这就意味着,无论按何种顺序将树中所有结点存储到数组中,结点的存储位置都无法直接反映逻辑关系。所以,简单的顺序存储结构是不能满足树的实现要求的。

不过充分利用顺序存储和链式存储结构的特点,完全可以实现对树的存储结构的表示。这里介绍三种不同的表示法:双亲表示法、孩子表示法、孩子兄弟表示法

6.3.1 双亲表示法

人可能因为某些原因没有孩子,但一定有父母。树这种数据结构也一样,除了根结点外,其余每个结点,不一定有孩子,但是一定有且仅有一个双亲。

我们假设以一组连续空间存储树的结点,同时在每个结点中,附设一个指示器指示双亲结点在数组中的位置。也就是说,每个结点除了知道自己是谁以外,还知道它的双亲在哪里。结点结构如下图。

其中data是数据域,存储结点的数据信息。Parent是指针域,存储该结点的双亲在数组中的下标。

以下是双亲表示法的结点结构定义代码。

由于根结点是没有双亲的,所以我们约定根结点的位置域设置为-1,由此所有的结点都存有它双亲的位置。如图。

这样的存储结构,我们可以根据结点的parent指针很快找到它的双亲结点,时间复杂度为O(1)。但如果要找结点的孩子,需要遍历整个结构。

我们可以改进一下,增加一个结点最左边孩子的域,不妨叫它长子域,如果没有孩子结点,这个长子域就设置为-1.

对于有0个或1个孩子结点来说,这样的结构是解决了要找结点孩子的问题了。甚至是有2个孩子,知道了长子是谁,另一个当然就是次子了。

另外一个问题场景,我们很关注各兄弟之间的关系,双亲表示法无法体现这样的关系。因此,我们可以增加一个右兄弟域来体现兄弟关系,也就是说,每一个结点如果它存在右兄弟,则记录下右兄弟的下标。同样的,如果右兄弟不存在,则赋值为-1。

但如结点的孩子很多,超过2个。我们又关注结点的双亲、又关注结点的孩子、还关注结点的兄弟,而且对时间遍历要求还比较高,那么我们还可以把次结构扩展为有双亲域、长子域、再有右兄弟域。存储结构的设计是一个非常灵活的过程。一个存储结构设计得是否合理,取决于基于该存储结构的运算是否合适、是否方便,时间复杂度好不好等。注意也不是越多越好,有需要时再设计相应的结构。

6.3.2 孩子表示法

孩子表示法:把每个结点的孩子结点排列起来,以单链表作存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。如图。

为此,设计两种结点结构,一个是孩子链表的孩子结点。

其中child是数据域,用来存储某个结点在表头数组中的下标。next是指针域,用来存储指向某结点的下一个孩子结点的指针。

另一个是表头数组的表头结点。

其中data是数据域,存储某结点的数据信息。firstChild是头指针域,存储该结点的孩子链表的头指针。

以下是孩子表示法的结构定义代码。

这样的结构对于我们要查询某个结点的某个孩子,或者找某个结点的兄弟,只需要查找这个结点的孩子单链表即可。对于遍历整棵树也是很方便的,对头结点的数组循环即可。

但是,如果想知道某个结点的双亲是谁,就需要遍历整棵树,这里我们可以改进一下,综合双亲表示法和孩子表示法,如图。

6.3.3 孩子兄弟表现法

孩子兄弟表示法:任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我们设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。

结点结构如图:

其中data是数据域,firstchild为指针域,存储该结点的第一个孩子结点的存储地址,rightsib是指针域,存储该结点的右兄弟结点的存储地址。

结点定义代码如下:

这种方法实现如下图:

这种表示法,给查找某个结点的某个孩子带来了方便,只需要通过firstchild找到此结点的长子,然后再通过长子结点的rightsib找到它的二弟,接着一直下去,直到找到具体的孩子。

但如果想找某个结点的双亲,这个表示法也是有缺陷的。不过我们可以增加一个parent指针域来解决快速查找双亲的问题,和之前一样,这里不再细讲。

其实这个表示法最大的好处是把一棵复杂的树变成了一棵二叉树。上图可以变形成下图所示。

6.4 二叉树的定义

二叉树 (Binary Tree) 是 n (n≥0) 个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。

6.4.1 二叉树特点

  • 每个结点最多有两棵子树,所以二叉树中不存在度大于2的结点。
  • 左子树和右子树是有顺序的,次序不能任意颠倒。
  • 即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。

二叉树具有五种基本形态:

  1. 空二叉树
  2. 只有一个根结点
  3. 根结点只有左子树
  4. 根结点只有右子树
  5. 根结点既有左子树又有右子树

区分:如果是有三个结点的树,有几种形态?如果是有三个结点的二叉树。又有几种形态?

若只从形态上考虑,三个结点的树只有两种情况,如下图,分别是有两层的树1和有三层的后四种的任意一种,但对于二叉树来说,由于要区分左右,所以就演变成五种形态,树2、树3、树4和树5分别代表不同的二叉树。

6.4.2 特殊的二叉树

 斜树

所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫右斜树。这两者统称为斜树。

满二叉树

在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上这样的二叉树称为满二叉树。

完全二叉树

对一棵具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置相同,则这棵二叉树称为完全二叉树,如图。

完全二叉树有以下几个特点:

  1. 叶子结点只能出现在最下两层。

  2. 最下层的叶子一定集中在左部连续位置。

  3. 倒数第二层,若有子节结点,一定都在右部连续位置

  4. 如果结点度为1,则该结点只有左孩子,即不存在只有右子树的情况。

  5. 同样结点数的二叉树,完全二叉树的深度最小。

如下图三种树就不是完全二叉树(注意浅色结点表示不存在),因为它们编号间出现了空档。

6.5 二叉树的性质

性质1

在二叉树的第i层上至多有2i-1个结点(i≥1)。

性质2

深度为k的二叉树至多有2k-1个结点(k≥1)。

等比数列求和:1+2+22+23+······+2k-1=2k-1

性质3

对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。

终端结点数其实就是叶子结点数,而一棵二叉树,除了叶子结点外,剩下的就是度为1或2的结点数了,我们设n1为度是1的结点数。则数T结点总数n=n0+n1+n2。如图。

再换个角度,数一数它的连接线数,由于根结点只有分支出去,没有分支进入,所以分支线总数为结点总数减1。上图就是9个分支,10个结点。对于A、B、C、D结点来说,它们都有两个分支线出去,而E结点只有一个分支线出去。所以总分支线为4×2+1×1=9。

用代数表达就是分支线总数=n-1=n1+2n2。联立上面的n=n0+n1+n2,可以推导出n0=n2+1。

性质4

具有n个结点的完全二叉树的深度为[log2n]+1([x]表示不大于x的最大整数)。

对于完全二叉树,它的结点数一定小于等于同样深度的满二叉树的结点数2k-1,但一定多于比它少一深度的满二叉树的结点数2k-1-1。即满足2k-1-1<n≤2k-1。由于结点数n是整数,得2k-1≤n<2k,取对数得k-1≤log2n<k,而k作为深度也是整数,因此k=[log2n]+1。

性质5

如果对一棵有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。

结合下图进行理解:

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值