【数据结构与算法】(9):树与二叉树的概念、性质及详细证明

🤡博客主页:醉竺

🥰本文专栏:《数据结构与算法》

😻欢迎关注:感谢大家的点赞评论+关注,祝您学有所成!


✨✨💜💛想要学习更多数据结构与算法点击专栏链接查看💛💜✨✨  


目录

一.树的概念和结构

1.1 树的概念

1.2 树相关的基本术语 

1.3 树的表示(存储结构)

1.4 树的实际应用

二.二叉树的概念及结构 

2.1 概念 

2.2 现实中的二叉树 

2.3 特殊的二叉树 

2.3.1 满二叉树

2.3.2 完全二叉树   

2.3.3 斜树 

2.4 二叉树的性质和证明

三.小结 


一.树的概念和结构

1.1 树的概念

        在日常生活中,树是一种随处可见的植物,它由树根、树枝、树叶这些主要结构组成。而“树 形结构”,就是基于日常生活中的树而得名的一种非线性数据结构。

        什么是“非线性的数据结构”?在实际场景中,常常存在着一对多,甚至是多对多的情况。想象一下,一根树枝可以分叉出很多树枝、树叶,我们也可          以 将“非线性的数据结构”理解成一种一对多的关系,而不是像一条线一样,按顺序排列的一对一关系。 例如下面两个生活中的例子就符合树形结构。

        在数据结构中,树的定义为:树是一种非线性的数据结构,它是由n(n>=0)个有限节点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 

  • 当 n=0 时,树就是一棵空树;
  • 如果树为非空,那么就会有两种情况:
  • 一种,就是 n=1 的时候,有且只有唯一一个称为根 / 树根(Root)的特殊节点;
  • 另一种就是,当 n>1 时,除根节点外,其余节点可以分为 m(m>0)个互不相交的有限集 T1、T2、…、Tm,其中每个集合自身又是一棵树,它们叫做根的子树,因此,树是递归定义的。上图中节点 A 就是树根 / 根节点
  • 注意,一棵树可以只有树根而没有其他节点。 

        如下图,树的节点数量(n>1时)的情形。该树除了树根之后,又分成了3个互不相交的集合T1,T2和T3,这3个集合本身又各是一棵树,称为根的子树。

        根据树的定义,我们可以知道,树的数据结构有如下特点:

树的特点:

  1. 树的定义是递归的,是一种递归的数据结构
  2. 树在逻辑结构上属于非线性结构
  3. 树的根节点没有前驱结点,除根节点以外的所有结点有且只有一个前驱结点
  4. 树的叶结点没有后继结点,除叶结点以外的所有结点都有一个或多个后继结点

        注意:树形结构中,子树之间不能有交集,否则就不是树形结构! 

1.2 树相关的基本术语 

        以下基本术语不需要死记硬背,只需要理解就好,将来忘记了可以随时来回顾。但是也一定要比对着图片耐心读一遍,理解着记忆。

  1. 节点拥有的子树的个数,叫做节点的度(Degree),比如上图中节点 A 的度是 2,节点 B 的度为 3,节点 C 的度为 1。
  2. 如果度为 0,那么这个节点就叫做叶节点(Leaf)终端节点,上图中节点 H、I、J、K、 G 节点都是叶节点。相反,度不为 0 的节点称为分支节点非终端节点。除根节点外的分支节点也称为内部节点
  3. 树的度是树内各节点度的最大值,上图中节点 B 或者节点 D 的度都为 3,是节点度的最大 值,因此,树的度也是 3。
  4. 节点的子树的根称为该节点的子节点(Child),上图中节点 A 的子节点是节点 B、C,而节点 B 的子节点是节点 D、E、F。同样,节点 B、C 的父节点(Parent)双亲节点就是节点 A,节点 D、E、F 的父节点就是节点 B。
  5. 节点的层次(Level)是从树根开始算起的,根为第一层,根的孩子为第二层,以此类推, 某个节点位于第 i 层,其子树就位于第 i+1 层。图 1 中节点 A 为第一层,节点 B、C 为第 二层,节点 D、E、F、G 为第三层,节点 H、I、J、K 为第四层。树的高度深度 (Depth)是树中节点最大层数,因此图 1 树的深度是 4。
  6. 相同父节点的孩子之间互称兄弟节点(Sibling),比如 D、E 节点是兄弟节点,H、I 节点 也是兄弟节点。层次相同但父节点不同的孩子之间互称堂兄弟节点,比如图 1 中节点 F 与 节点 G,节点 J 与节点 K。 
  7. 堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:B、C;D、E、F
  8. 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
  9. 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
  10. 森林:由m(m>0)棵互不相交的树的集合称为森林; 

 除此之外,关于“树”,还有三个比较相似的概念:高度(Height)、深度(Depth)、层(Level)。它们的定义是这样的:

这三个概念的定义比较容易混淆,描述起来也比较空洞。我举个例子说明一下,你一看应该就能明白。

记这几个概念,我还有一个小窍门,就是类比“高度”“深度”“层”这几个名词在生活中的含义。

在我们的生活中,“高度”这个概念,其实就是从下往上度量,比如我们要度量第 10 层楼的高度、第 13 层楼的高度,起点都是地面。所以,树这种数据结构的高度也是一样,从最底层开始计数,并且计数的起点是 0。

“深度”这个概念在生活中是从上往下度量的,比如水中鱼的深度,是从水平面开始度量的。所以,树这种数据结构的深度也是类似的,从根结点开始度量,并且计数起点也是 0。

“层数”跟深度的计算类似,不过,计数起点是 1,也就是说根节点的位于第 1 层。

1.3 树的表示(存储结构)

        树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,既然保存值域,也要保存结点和结点之间的关系。树形结构是一对多的关系,除了树根之外,每一个节点有唯一的直接前驱(双亲),除了叶子之外,每一个节点有一个或多个直接后继(孩子)。那么如何将数据以及它们之间的逻辑关系存储起来呢? 

        实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法 等。我们这里就简单的了解其中最常用的孩子兄弟表示法

        每个结点包含三部分内容:指向第一个孩子节点的指针 结点值指向节点下一个兄弟节点的指针。 孩子兄弟表示存储结构如下图所示:

以下图为例,其孩子兄弟表示法 如图所示:

A 有3个孩子 B、C 和 D,其长子(第一个孩子) B 作为 A 的左孩子,B 的右指针存储其右兄弟 C,C的右指针存储其右兄弟 D。
B 有2个孩子 E 和 F,其长子 E 作为 B 的左孩子,E 的右指针存储其右兄弟 F。
C 有1个孩子 G,其长子 G 作为 B 的左孩子。
D 有2个孩子 H 和 I,其长子 H 作为 D 的左孩子,H 的右指针存储其右兄弟 I。
G 有1个孩子 J,其长子 J 作为 G 的左孩子。

孩子兄弟表示法的秘诀:长子当作左孩子,兄弟关系向右斜。 

用代码表示: 

typedef int DataType;
struct Node
{
 struct Node* _firstChild1; // 第一个孩子结点
 struct Node* _pNextBrother; // 指向其下一个兄弟结点
 DataType _data; // 结点中的数据域
};

1.4 树的实际应用

        树的实际应用有很多,例如,表示文件系统的目录就是树结构 


二.二叉树的概念及结构 

2.1 概念 

        树的结构多种多样,对树的操作也各不相同,但最常用是二叉树,因为大部分树都可以转换为 二叉树。 

        那什么是二叉树呢?二叉树的特点是每个节点最多有两棵子树(左子树右子树),这意味着每个节点的度(节点拥有子树的个数)都不大于2。它的两棵子树有左右之分。想象一下,人的脚是分左右的,右脚不能穿左侧的鞋,和二叉树两棵子树的左右之分是一个道理。另外,次序也是不能随意颠倒的, 这表明二叉树是一棵有序树

        这里,我们给二叉树下一个明确的定义: 二叉树是 n(n≥0)个节点的有限集合,该集合或者 为空集(即 n=0,叫做空二叉树),或者由一个根节点和两个互不相交的该根节点的 左子树 和 右子树 构成,左子树和右子树又分别是一棵二叉树。 

        注意:对于任意的二叉树都是由以下几种情况复合而成的: 

        二叉树的结构最简单,规律性最强,因此通常被作为重点讲解。 

2.2 现实中的二叉树 

2.3 特殊的二叉树 

        二叉树有一些特殊的形态在后面会经常被提到或者用到,这里我先带你认识一下满二叉树完全二叉树以及斜树

2.3.1 满二叉树

下图就是一棵满二叉树: 

观察上图,我们先说下满二叉树有什么特点。

1. 所有的分支节点都存在左子树和右子树(非叶节点的度一定是 2)。

2. 所有的叶子都在同一层上(这也意味着叶节点只能出现在最下一层)。

3. 不存在度为非 0 和非 2 的节点。

可以看到,满二叉树看上去是很平衡的。在同样高度的二叉树当中,满二叉树一定是节点个数最多,叶子数最多的二叉树。

那要怎么去定义“满二叉树”呢?观察一下,图 5 中,第一层有 1 个节点,第二层有 2 个节 点,第三层有 4 个节点,第四层有 8 个节点,所以总共的节点数为 1+2+4+8=15 个,即 2^{4}-1 个。  

由此,我们可以给出满二叉树的定义:

满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 2^{k}-1,则它就是满二叉树。

2.3.2 完全二叉树   

        完全二叉树理解起来有一点难度。我们先看下图,下图就是一棵完全二叉树。 

观察上图,想一想,完全二叉树有什么特点呢? 

1. 叶节点都在最底下两层。

2. 最后一层的叶节点都靠左侧排列(左侧连续),并且除最后一层,其他层的节点个数都要达到最大。

3. 倒数第二层如果有叶节点,则叶节点都靠右侧排列(右侧连续)。 

4. 如果节点度为 1,则该节点只有左子树,不可以只有右子树。而且最多只有一个度为 1 的 节点。 

可以看到,满二叉树一定是一棵完全二叉树,但完全二叉树不一定是满二叉树。 

完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。现在,我们可以借助满二叉树的概念,给出完全二叉树的定义:

完全二叉树:对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

也就是说,完全二叉树除了最后一层,前面每一层都是满的,最后一层必须从左向右排列。也就是说,如果一个节点没有左孩子,就不可以有右孩子。

如何判断一棵二叉树是不是完全二叉树呢?如下图所示的几棵二叉树就都不是完全二叉树: 

        上图中,第一棵树的节点 5 缺少左子树(编号 10),第二棵树的节点 3 缺少两棵子树(编号 6、7),第三棵树的节点 5 缺少两棵子树(编号 10、11)。 

        所以,如何判断是否是完全二叉树,就可以按照下面的步骤去做。 

        在看到一棵树后,按照满二叉树的情形给该二叉树的节点进行逐层按顺序编号,如果编号出现了空缺,就不是完全二叉树,否则就是完全二叉树。

        一棵满二叉树,依次把编号最大的 1 到多个节点去掉(比如去掉上面的完全二叉树图中的 15、14、13 节 点),得到的就是一棵完全二叉树。  

2.3.3 斜树 

        所有节点都只有左子树的二叉树叫左斜树。所有节点都只有右子树的二叉树叫右斜树。这两种 树统称斜树。 斜树的特点是每一层只有一个节点,节点个数与二叉树深度相同。这种树看起来更像线性表。 下图中第 1 棵是左斜树,第 2 棵树是右斜树。 

2.4 二叉树的性质和证明

        在对二叉树进行编码过程中,尤其是涉及开辟多少空间保存数据的时候,往往会用到二叉树的性质。下面汇总来说,然后再证明。 

性质一:若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^{i-1} 个结点.

性质二:若规定根节点的层数为1,则深度为k的二叉树的最多有 2^{k}-1个节点

性质三二叉树节点的总数量等于节点的总度数 +1

性质四:对任何一棵二叉树, 如果度为0的叶子节点个数为 n_{0} , 度为2的节点数为n_{2} ,则叶节点的数量比有两有两棵子树的节点数量多一个,即n_{0}=n_{2}+1

性质五:若规定根节点的层数为1,具有 n 个节点的完全二叉树的高度 kk=\left \lceil log_{2}^{(n+1)} \right \rceil或者k=\left \lfloor log_{2}^{n} \right \rfloor+1

注:   符号⌈X⌉表示向上取整,也就是比 X 大的最小整数。如果 X 本身是整数,那么⌈X⌉就等于本身。 

        符号⌊X⌋表示向下取整,也就是比 X 小的最大整数。如果 X 本身是整数,那么⌊X⌋就等于本身。

性质六:对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号则编号为i的节点有: 

  1. 若 i>0,i 位置节点的双亲序号:(i-1)/2;(若 i=0,i则是根节点的编号,无双亲节点)
  2. 若 2i+1<n,左孩子序号:2i+1;(若2i+1>=n,则无左孩子)
  3. 若 2i+2<n,右孩子序号:2i+2;(若2i+2>=n,则无右孩子)

以下是上述几个性质的证明,感兴趣的可以看一看,也不难,有助于理解记忆。

性质一的证明:

        例如,一棵二叉树如下图所示。由于二叉树每个节点最多有2个孩子,第一层树根为1个节点,第二层最多为2个节点,第三层最多有4个节点,因为上一层的每个节点最多有两个孩子,因此当前层最多是上一层节点数的2倍。 

使用数学归纳法证明如下。

i=1时:只有一个根节点,2-1=2^{0}-1

i>1时:假设第 i-1 层有2^{i-2}个节点,而第 i 层节点数最多是第 i-1层的2倍,即第 i 层节点数最多有2*2^{i-2}=2^{i-1}

性质二的证明:

        如果深度为k的二叉树,每一层都达到最大节点数,也就是满二叉树,把每层的节点数都加起来就是整棵二叉树的最大节点数。

性质三的证明:

        观察一棵二叉树不难发现,除根节点外,每个节点头上都有一个分支 / 树枝(每个节点都有一 个父节点),那么一棵二叉树节点总数量其实就是这些分支的总数量 +1,之所以 +1,是因为根节点头上没有分支。一棵二叉树节点的总度数,其实就是每个节点头上分支的总数量,所以得出性质三的结论:二叉树节点的总数量 = 节点的总度数 + 1。 下面性质四的部分证明中也有性质三的证明,可以继续往下读。

性质四的证明:

         二叉树中的节点度数不超过2,因此一共有3种节点,即度为0、度为1、度为2。设二叉树总的节点数为n,度为0的节点数为n_{0},度为1的节点数为n_{1},度为2的节点数为n_{2},总节点数等于3种节点数之和,即n=n_{0}+n_{1}+n_{2}。 而总节点数又等于“分支数b+1”,即 n=b+1。为什么呢?如下面左图所示,从下向上看每一个节点对应一个分支,只有树根没有对应分支,因此总的节点数为“分支数b+1” 。

        而分支数b怎么计算呢? 

        如下面右图所示,从上向下看,每个度为2的节点产生2个分支,度为1的节点产生1个分支,度为0的节点没有分支,因此分支数b=n_{1}+n_{2},则 n=b+1=n_{1}+2n_{2}+1。而前面已经得到 n=n_{0}+n_{1}+n_{2},两式联合得:n_{0}=n_{2}+1.

性质五的证明:

        假设完全二叉树的深度为k,那么除了最后一层外,前k-1层都是满的,最后一层最少有一个节点,如下图所示。最后一层最多也可以充满节点,即2^{k-1}个(此时完全二叉树就是满二叉树)。所以一个具有n个节点的完全二叉树,它的节点数量的范围为:2^{k-1}\leqslant n\leqslant 2^{k}-1,右边放大后,2^{k-1}\leqslant n< 2^{k},同时取对数,k-1\leqslant log_{2}^{n}< k,所以k=\left \lfloor log_{2}^{n} \right \rfloor+1。其中,\left \lfloor \right \rfloor 表示取下限,\left \lfloor x \right \rfloor表示小于x的最大整数,如\left \lfloor 3.6 \right \rfloor=3

 这里截取另一个证明方式,跟上述方法基本类似。 

性质六无需证明,很简单,可以自己画图算算。 

三.小结 

        本篇的内容,我们尝试描述了树形结构,也给出了许多和它相关的基本概念,其中比较重要的概念 是树根、子树、节点的度,叶节点、子节点、父节点、兄弟节点、树的高度这几个部分。之后引入了二叉树的概念。可以说,二叉树在树形结构中最常用,所以本篇内容以及后面文章还会用很多篇幅讲述二叉树相关的知识。这一篇文章将重点放在了认识各种形态的二叉树上,比如理解满二叉树、完全二叉树、斜树的概念。 

        然后,则是二叉树性质的学习。也许你会觉得这些性质离实际应用太过遥远,但其实它对于后面编写程序时决定内存空间分配多少、二叉树的高度和节点数量如何计算以及如何寻找某个节 点的父或子节点等都具有重要的指导意义,这一点在后续编写代码时你会越来越清楚。

        当然,这些性质不要死记硬背,理解性记忆即可,后面的课节中编程时会偶尔用到二叉树的性 质。如果你忘记了这些性质,随时复习一下本节内容也就可以了。 

        最后,如果您觉得本篇文章对你起到了一点点的帮助,希望您能点个赞,或者收藏一下,鼓励下我,这对我很重要❤️。

        点击本篇文章最开始介绍栏目的数据结构与算法专栏链接,继续学习阅读下篇有关二叉树的内容吧,下一篇将会根据二叉树的存储结构和性质,对二叉树进行编码实战。✨✨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醉竺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值