树是一种经常用于标识分层数据的数据结构,树可以被定义为以节点链接在一起的非线性的集合实体,它是一个分层结构。
二叉树
树中的每个节点至多有2个节点,我们称该树是一棵二叉树,每个节点的2个节点分别叫左子节点和右子节点。
template
根据上面的代码定义,我们进一步延伸几个关于树的术语
![2bdb7a6617577107dd1dc7ce2baeb9c1.png](https://i-blog.csdnimg.cn/blog_migrate/dc829a2f6031b10d6c460ab8c5ceb464.jpeg)
根:树中的最顶层的节点是整棵树的根(Root),上图的节点A。
节点:以根节点延伸所链接在一起的其他节点,如上图有节点B、C、D、J、K、L、M。
子节点:例如上图的节点B、C是节点A的子节点。节点C其实有两个子节点,但它们都是NULL。
内部节点:其左、右子节点至少一个不为NULL的节点。例如上图的B、D、E都是内部节点。
叶子节点:例如上图的节点B、J、K、L、M这些是叶子节点,他们没有下一级的节点,因为他们的子节点属性都是NULL。
二叉树的特殊形式以及基本属性
- 完满二叉树:如果每个节点有0或2个子节点,则该二叉树就是完满二叉树(Fulled Binary Tree)或叫严谨二叉树(Stricted Binary Tree 或叫Proper Binary Tree)。 以下是三个图都是完满二叉树的示例。
- 完美二叉树(Perfect Binary Tree):所有内部节点都有2个子节点,并且所有叶节点都处于同一个最高级别。
- 完整二叉树(Complete Binary Tree):从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,但最高层的所有叶子节点必须居左填满。
![e60cb4cbfdfb890f7fdcdb727d10ee4f.png](https://i-blog.csdnimg.cn/blog_migrate/8d746e7d27c14e4a1008f6700a9d1e90.jpeg)
三种二叉树的关系:完美二叉树属于完整二叉树的一个子集,完整二叉树属于完满二叉树的一个子集。
还有一个非常特殊的二叉树,请记住,二叉树唯一的必要条件是每个节点不能超过2个子节点。但是这种从形态上接近单链表的二叉树形态具有最差时间开销。
![293c7267a2d751ece486bb5bb237b6e7.png](https://i-blog.csdnimg.cn/blog_migrate/35e3d5c3c9b363dcf96623323fc0947c.png)
好了,再看一下图,这并非一个完整二叉树,因为子节点D的具有1个右子节点,右边是一个空节点。请记住完整二叉树的必要条件是
- 所有内部节点都明确有两个子节点。
- 所有叶子节点在最高级别的节点组。
- 在最高level的节点组:所有叶子节点从左必须连续填满,右边允许有空的节点
![992011d3bdc093d2d9628677fc198f77.png](https://i-blog.csdnimg.cn/blog_migrate/aa8f2fac27e11f1089d3683edda3aa38.png)
高度(Height):就是从根节点到指定子节点的路径长度,也叫深度(Dept)或级别(Level),但这是一个相对的概念,其参照物当然是计算该路径的起始节点和结束节点。我们列举一些例子
![d3dceffb47de48b7669d47526083dda6.png](https://i-blog.csdnimg.cn/blog_migrate/5f8909957f7e3d37ca6b2a9439f07610.jpeg)
笔者提醒:离开其参照对象谈论“高度”或“深度”都是扯蛋。
当我们说节点的高度:例如节点A到节点B的路径长度是1,我们说节点B的高度是1。同理,节点C的高度是1,我们说节点B和节点C都属于Level 1的节点组,因为他们的深度都为1。同理,节点D、E、F、G都属于Level 2的节点组;H、I、J同属Level 3的节点组。
当我们说二叉树的高度时,那么其参照标准就是从根节点到任意叶子节点的最长路径长度,在上图左边的二叉树中,符合该定义的路径有三组,那么我们就说该二叉树的高度为3
- A->B->D->H
- A->B->E->I
- A->B->E->J
而A->C->F和A->C->G是路径是2不符合二叉树最长路径的定义,故此,不被采纳为该二叉树的高度,但是它是该二叉树的最短高度。
上图右边的树叫做完美二叉树(Perfect Binary Tree),为什么冠以Perfect的头衔?因为它的左右子树的所有节点的路径都是逻辑上对称的。
推论:完美二叉树中,所有叶子节点的深度都是一样的,换句话说,二叉树的高度等于其叶子节点的深度。
那么为推论有效性的背赎基于如下事实。
- 空节点的高度约定为-1,即空树的高度。
- 节点本身的高度为0,因为其参考的起始节点和结束节点都是它本身。
- 从上面一条,引申出根节点的高度为0。
关于Level的起始值是0还是1的争议!!
我说过高度(或叫级别)是一个相对的概念。
- 如果计算高度是从根节点到叶子节点的"路径的边缘计数"为标准,则level的起始值则为0,因此单个节点没有任何边缘,因此为0。
- 计算高度是从根节点到叶子节点的"路径上的节点数"为标准,则level的起始值则为1。因为单个节点数为1。
- 不论上面以那种标准计算树的高度,空节点或(叫空树)的高度都约定为-1。
提醒:本文如没特别注明,采用的level计算的标准是“路径的边缘计数”,有些博主的同类文章认为从根节点开始就约定为Level 1,实质上是以"路径上的节点数"为准。
国内很多培训机构用在教育学员普片用的第2种标准,笔者个人认为是很扯蛋的,两点确定一线,那么逻辑上就只有一个单位长度。难度这个小学逻辑不正确吗!?何来是2!! 只有一个节点的情况下,对于节点本身来说当然是0,何来1!? 笔者就是看不惯一些”绝对正确“的教条训话。
显然,本文谈论油管二叉树的高度是采用--从根节点到叶子节点的"路径的边缘计数"为标准的。因此我们再次复习一下该图有关不同二叉树形态的高度。下图所有二叉树形态的高度都为3.
![b62a4181990cac307a6bf6ca25bef527.png](https://i-blog.csdnimg.cn/blog_migrate/7de162258e9dca669a6ce75166f21061.jpeg)
二叉树的一般特征
以下是两个特征是所有二叉树的共性,以下两个公式成立的前提均以level起始值为0为条件.
- 特征1:若二叉树的层次从0开始(i>=0),则在二叉树的第i层至多有2^i个结点,这里用M表示,对于根节点,其节点数为1。
- 特征2:高度为i的二叉树最多有2^(i+1) - 1个结点(i>=0)。 其实这是一个关于2的幂运算所组成的几何级数序列的和
完美二叉树的特性
由于完美二叉树是所有级别的节点都是完全填满的,完全符合上面二叉树的特性。即完美二叉树的节点数等于其最大节点数。
- 若完美二叉树的级别为h,那么它的节点总数,这里用N表示,例如level为0的节点数0.level为3时,其节点数为15
- 完美二叉树的高度和所有叶子节点的level是相同的。我们按照上面公式得到一个关于计算完美二叉树的高度h的反函数公式。
证明:完整二叉树的高度计算公式的证明
我们这里设定计算高度是从根节点到叶子节点的"路径的边缘计数"为标准,即级别起始值为0,
设N为完整二叉树中的最大节点数,没必要知道完整二叉树节点数。因为
- 完整二叉树的最大节点数等于与其同等高度的完美二叉树的节点数
- 完美二叉树的最高层的叶子节点数,我们可以轻松通过公式求得。
我们只需使用上面两个性质可以证明完整二叉树的高度计算公式
lk表示级别k的节点数,其中级别编号为0、1、2、3、...,h。 最后一级h表示树的高度。
证明:根据完整二叉树的定义可知,level 0 到h-1的是子树一个完美二叉树,其节点数是明确的,我们设level 0 到h-1的节点数为S。
那么第k级别的节点数据是第k-1级别的节点数的2倍。因为级别0到h-1内的每个内部节点明确有两个非空节点。即,这是一个等价于比值为2的等比序列。
根据等比序列的求和公式,可知S表示等级0到h-1的节点数:
又因为根据二叉树的第h层的最大节点数的公式可知
那么上面N=S+M可以得到
即,根据等比序列的前h项和公式可得
即,我们取其反函数可以变换得到该公式,注意该公式是计算根节点到叶子节点的"路径的边缘计数"为标准的
补充:如果计算高度是从根节点到叶子节点的"路径上的节点数"为准,其公式的变体形式只需在上面形式+1即可。
当二叉树满足是完整二叉树时,并且其节点数N个是常数的,那么完整二叉树时可以以下公式算出该树木的最低高度h的公式 。该公式的证明,可以用数学归纳法去证明。笔者就省略该过程。
该公式的计算结果是从根节点到叶子节点的"路径的边缘计数"为准
证明:完美二叉树的高度和最低高度的关系
因为完美二叉树的节点总数等于最大节点数,因此都设其数量为N
即完美二叉树的高度
欲证
令h=0时,
令h=1时,
令h=2时,
.....
令
因为k是一个整数,那么
令
同理,k属于整数,那么,左边
综上所术,在完美二叉树中,
特征:完美二叉树的高度恒等于其最小高度。
证明:完整二叉树的高度和最小高度的关系
前面的证明中,已经提到高度为
即
又因为从前面已证的完整二叉树的高度,即
根据,对数的运算性质可知
所以,完整二叉树的高度和最小高度关系:
练习1:请读者思考下图左边的二叉树能否套用被证明完整二叉树的高度计算公式?
答案:显然,是不能的因为它不是完整二叉树,请牢记完整二叉树的构成条件。
练习1:请读者思考下图中间的二叉树能否套用被证明完整二叉树的高度计算公式?
答案:可以,因为该树是完美二叉树,完美二叉树就是完整二叉树的一个子集。
![833f85e954d657995d651fee9ca48292.png](https://i-blog.csdnimg.cn/blog_migrate/e819d6342b2d44d1467d4a1f14ea4109.jpeg)
我们说同样的节点数N的二叉树,如果是上面右图的形态,我们说这样的二叉树的最大高度可以通过如下
完美二叉树的节点数与内部节点索引的关系。
我们来讨论一下节点完美二叉树的节点个数跟各个索引的关系。
![0da926b483c1f25466a06b0f91daef46.png](https://i-blog.csdnimg.cn/blog_migrate/0cefdaedf86fe599e466374dc095864b.png)
我们设j是根据人可阅读的习惯按照从左到右,从第0层到最高层的顺序标记各个节点的序号。那么可以得出,当前内部节点的索引、与其左子节点、右子节点、父节点的索引运算关系。
注:根节点的父节点约定为NULL
![c90cd91609778cab8eac37206f0c338e.png](https://i-blog.csdnimg.cn/blog_migrate/103b299260bbef4a41cc87ae7831ba43.png)
在使用编程语言实现时,计算机通常其索引是以0为起始值的,我们只需在代码实现时,将上表各列的的一般公式表达式减1即可。得到代码实现通用的版本。
![836cae7249ca1a9e054fd7d44e8981a4.png](https://i-blog.csdnimg.cn/blog_migrate/594449bd8cba145e722985d6cc2a2cb9.png)
令
左子节点的索引为 :
右子节点的索引为:
父节点的索引为:
二叉树的性能开销
当我们分析各种操作的性能开销时,二叉树的相关的数学公式非常必要,二叉树在时间上的大量操作成本取决于完美二叉树的高度。在二叉搜索树当中其查找、插入和删除元素的时间开销与树的高度成比例的。我们希望树的高度尽可能地少。
如果树越密集,树的高度就越少。该树越接近完美二叉树或完整二叉树。一颗具有N个节点的完整二叉树的最小高度。根据上文的高度计算公式,我们可以其时间复杂度设为T,即公式如下:
平衡二叉树
我们分析二叉树逻辑上是否对称,可以对二叉树内任一个节点的左子树和右子树之间的高度差来衡量其对称性。这种方法我们叫二叉树平衡分析法。当一个二叉树的是平衡二叉树,那么它的时间复杂度就接地或等于
设某个二叉树内的任一节点为X ,X节点的左子数的高度为
当二叉树内任意节点
在考察二叉树的时间复杂度,经常需要用到下面两个性质。
- 性质1:当X节点是一个叶子节点,那么其左右子树都为NULL,因为约定空树的高度为-1,那么空叶子节点的
- 性质2:当X节点是二叉树的任一内部节点,那么其左右子节点都不为NULL,因此X节点都其左子节点的高度为1,同理其右子节点的高度为1,那么内部节点的
对于完美二叉树中的各个内部节点的左右子树的高度差--常数K均为0
![1a6d65ca46cf41fd59d723a7afc2bc4d.png](https://i-blog.csdnimg.cn/blog_migrate/54e1637e6e4d5454b1d961b719fc55ac.png)
我们不妨分析一下上图,例如叶子节点N的左子节点为NULL、因此其高度为-1,其右子节点为NULL,同理高度为-1.那么节点N的高度差
同理,其余叶子节点都是得到同样的分析结果。
我们在看看Level 2的每个节点,例如D节点的左子节点和右子节点都为叶子节点。其高度各自为0,那么
同理,Level2、Level 1、Level 0的所有内部节点都得到同样的分析结果。
因此,我们说完美二叉树是平衡的二叉树。
例子2:读者可以自行思考下图给二叉树是C节点的高度差K为什么等于1?
![9f87dc8c9e88d6a3cf203f34599e1ce6.png](https://i-blog.csdnimg.cn/blog_migrate/8deaaf7e05f2e9cc3407f8814093ded2.jpeg)
图中所有第3层的节点组都是叶子节点,根据二叉树平衡分析方法的性质1,其节点组内的所有节点的K常数等于0
同理,第2层的节点组内节点D、E属于内部节点,根据性质2可知,他们的K常数等于0.而节点F属于叶子节点,根据性质1,K常数也等于0.
同理节点B是内部节点,其K常数等于0.
重点分析的是C节点,如果对二叉树平衡分析法不熟悉的同学,可以跟着读者的分析的思路。
- 首先分析以节点C为根的左子数的路径C->F->NULL的高度是=1+0=1,即以节点C为根的左子树的高度
- 然后分析以节点C为根的右子数的路径C->G->M->NULL的高度是=1+1+0=2,另外还有一条路径C->G->N->NULL=1+1+0=2,即以节点C为根的右子树的高度为2,即
- 最后就Easy啦,那么节点C的常数
。
因此,上面例2的二叉树仍然是一棵平衡二叉树。
例子3:读者可以自行思考下图给二叉树是B节点的高度差K为什么等于2?这个留个读者自行思考。笔者明确地说,这个例子的二叉树不是平衡的二叉树。
![0e4604998910cb01308d3c0cacc8f2f0.png](https://i-blog.csdnimg.cn/blog_migrate/906a651f3f218eee42c6761b53162d3b.png)
小结:
我们运用基本的高中代数证明了有关二叉树的所有特性,不要认为这些数学概念毫无用处,在实现二叉树内部的逻辑,会运用到二叉树有关的数学特性。