一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树

一 满二叉树

1.1 满二叉树

国内教程定义:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。

通俗讲: 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树。

如图所示:

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第1张图片

节点:就是一个图中的0、1、2~~14,这些就叫节点。

叶子节点:就是没有子节点的节点,比如图中的7、8、9~~14这些,0、1、2、3这些就不是叶子节点。

二 完全二叉树

2.1 完全二叉树

完全二叉树是一种特殊的二叉树,满足以下要求:

1.所有叶子节点都出现在 k 或者 k-1 层,而且从 1 到 k-1 层,每层必须达到最大节点数(即从1到k-1层每一层的节点数都得排满);

2.第 k 层可以不是满的,但是第 k 层的所有节点必须集中在最左边。 
需要注意的是不要把完全二叉树和“满二叉树”搞混了,完全二叉树不要求所有树都有左右子树,但它要求:

 2.1 任何一个节点不能只有右子树没有左子树

 2.2 叶子节点出现在最后一层或者倒数第二层,不能再往上

一张图对比下“完全二叉树”和“满二叉树”:

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第2张图片

当我们用数组实现一个完全二叉树时,叶子节点可以按从上到下、从左到右的顺序依次添加到数组中,然后知道一个节点的位置,就可以轻松地算出它的父节点孩子节点的位置。

应用场景:我们了解到完全二叉树的特点是:“叶子节点的位置比较规律”。因此在对数据进行排序或者查找时可以用到它,比如堆排序就使用了它。

三 二叉查找树

3.1 二叉查找树

二叉树的提出其实主要就是为了提高查找效率,比如我们常用的 HashMap 在处理哈希冲突严重时,拉链过长导致查找效率降低,就引入了红黑树

二分查找可以缩短查找的时间,但是它要求 查找的数据必须是有序的。每次查找、操作时都要维护一个有序的数据集,于是有了二叉查找树这个概念。

二叉查找树:

1.若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

2.若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;

3.左、右子树也分别为二叉排序树。

如下图所示:

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第3张图片

特点:二叉查找树中,左子树都比节点小,右子树都比节点大,递归定义。

3.2 二叉查找树的性能

在最好的情况下,二叉排序树的查找效率比较高,是 O(logn),其访问性能近似于折半查找;

但最差时候会是 O(n),比如插入的元素是有序的,生成的二叉排序树就是一个链表,这种情况下,需要遍历全部元素才行(见下图 b)

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第4张图片

 如果我们可以保证二叉排序树不出现上面提到的极端情况(插入的元素是有序的,导致变成一个链表),就可以保证很高的效率了。

四 平衡二叉树

4.1 AVL树

平衡二叉树(AVL 树),平衡二叉树的提出就是为了保证树不至于太倾斜,尽量保证两边平衡。因此它的定义如下:

  1. 平衡二叉树要么是一棵空树

  2. 要么保证左右子树的高度之差不大于 1

  3. 子树也必须是一颗平衡二叉树

也就是说,树的两个左子树的高度差别不会太。

4.2 案例说明

我们来讲解构造平衡二叉树的过程:

1.以 12 为根节点,当添加 24 为它的右子树后,根节点的左右子树高度差为 1,这时还算平衡,这时再添加一个元素 28:

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第5张图片

2.这时根节点 12 觉得不平衡了,我左孩子一个都没有,右边都有俩了,超过了之前说的最大为 1,不行,给我调整!于是我们就需要调整当前的树结构,让它进行旋转。

3.因为最后一个节点加到了右子树的右子树,就要想办法给右子树的左子树加点料,因此需要逆时针旋转,将 24 变成根节点,12 右旋成 24 的左子树,就变成了这样(有点丑哈哈):

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第6张图片

这时又恢复了平衡,再添加 37 到 28 的右子树,还算平衡: 

 一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第7张图片

4.这时如果再添加一个 30,它就需要在 37 的左子树:

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第8张图片

5.这时我们可以看到这个树又不平衡了,以 24 为根节点的树,明显右边太重,左边太稀,想要保持平衡就 24 得让位给 28,然后变成这样:

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第9张图片

丑了点,但的确保持了平衡。https://mp.weixin.qq.com/s/K_oGI2rl3epTirxkST5LVQ

依次类推,平衡二叉树在添加和删除时需要进行旋转保持整个树的平衡,内部做了这么复杂的工作后,我们在使用它时,插入、查找的时间复杂度都是 O(logn),性能已经相当好了。

 五 红黑树

5.1 红黑树

红黑树(Red Black Tree) 是一种自平衡二叉查找树,在进行插入和删除时需要通过旋转和重新着色来维持其红黑树的特性。红黑树是一种自平衡排序二叉树树中每个节点的值,都大于或等于在它的左子树中的所有节点的值,并且小于或等于在它的右子树中的所有节点的值,这确保红黑树运行时可以快速地在树中查找和定位的所需节点。

性质:

1.每个节点非红即黑; 
2、根节点是黑的; 
3、每个叶节点(叶节点即树尾端NULL指针或NULL节点)都是黑的; 
4、如果一个节点是红的,那么它的两儿子都是黑的; 
5、对于任意节点而言,其到叶子点树NULL指针的每条路径都包含相同数目的黑节点; 
6、每条路径都包含相同的黑节点;

一次聊个透彻:满二叉树、完全二叉树、二叉搜索树,二叉平衡树_第10张图片

 应用场景:

1、广泛用于C++的STL中,Map和Set都是用红黑树实现的; 
2、著名的Linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块,进程的虚拟内存区域都存储在一颗红黑树上,每个虚拟地址区域都对应红黑树的一个节点,左指针指向相邻的地址虚拟存储区域,右指针指向相邻的高地址虚拟地址空间; 
3、IO多路复用epoll的实现采用红黑树组织管理sockfd,以支持快速的增删改查; 
4、Nginx中用红黑树管理timer,因为红黑树是有序的,可以很快的得到距离当前最小的定时器; 
5、Java中TreeMap的实现;、

你可能感兴趣的:(java,算法,数据结构,算法)