淘先锋技术网

首页 1 2 3 4 5 6 7

二叉树

说起树,我们不得不说最有名的树,那就是二叉树,什么是二叉树呢?

二叉树(binary tree),是指树中的每个节点最多只有两个子节点的树。
在这里插入图片描述

当然,二叉树本身似乎没什么用,我们平时说的二叉树基本上都是指二叉查找树,或者叫有序二叉树、二叉搜索树、二叉排序树。

二叉查找树

二叉查找树(BST,binary search tree),就是在二叉树的基础上增加有序性,这个有序性一般是指自然顺序,有了有序性,我们就可以使用二叉树来快速的查找、删除、插入元素了。
在这里插入图片描述

比如,上面这颗二叉查找树,查找元素的平均时间复杂度为O(log n)。

但是,二叉查找树有个非常严重的问题,试想,还是这三个元素,如果按照A、B、C的顺序插入元素会怎样?
在这里插入图片描述

这是啥?单链表?没错,当按照元素的自然顺序插入元素的时候,二叉查找树就退化成单链表了,单链表的插入、删除、查找元素的时间复杂度是多少?O(n)。

所以,在极限情况下,二叉查找树的时间复杂度是非常差的。

既然,插入元素后有可能导致二叉查找树的性能变差,那么,我们是否可以增加一些手段,让插入元素后的二叉查找树依然性能良好呢?

答案是肯定的,这种手段就叫做平衡,这种可以自平衡的树就叫做平衡树。

平衡树

平衡树(self-balancing or height-balanced binary search tree),是指插入、删除元素后可以自平衡的二叉查找树,使得它的时间复杂度可以一直渐近于O(log n)。

比如,上面那颗树,按A、B、C插入元素后,做一次旋转操作,就可以再次变成查找时间复杂度为O(log n)的树。
在这里插入图片描述

但是,平衡树一直只是一个概念,直到1962年才由两个苏联人发明了第一种平衡树——AVL树。

严格来说,平衡树是指可以自平衡的二叉查找树,三个关键词:自平衡、二叉、查找(有序)。

AVL树

AVL树(由发明者Adelson-Velsky 和 Landis 的首字母缩写命名),是指任意节点的两个子树的高度差不超过1的平衡树。
在这里插入图片描述

比如,上面这颗树,就是一颗AVL树,不信你可以数数看,是不是每个节点的两个子树的高度差都不超过1。

是不是很难发现它真的是一颗AVL树,没错,这是AVL树的第一个缺点,不够直观,特别是节点个数多的时候。

第二个缺点,就是插入、删除元素的时候自平衡的过程非常复杂,比如,上面这颗树插入一个节点T:
在这里插入图片描述

我们从T往上找,它的父节点U,U的两颗子树的高度差为1,满足AVL树的规则,再往上,S的两颗子树的高度差为1,也满足规则,再往上,V的两颗子树的高度差为2,不满足规则,此时,需要一个自平衡的过程,该如何自平衡呢?

我下面给出图示,你可以试着理解一下:
在这里插入图片描述

红色节点表示旋转的轴。

经过两次旋转,让这颗树再次变成了AVL树,而且这只是其中一种插入场景,真实的情况还要根据插入的位置的不同做不同的旋转,你可以多插入几个节点自己尝试平衡一下。

同样地,AVL树的代码也不是那么好实现的。

基于这些缺点,所以,后来又发展出来了各种各样的神奇的平衡树。

2-3树

2-3树,是指每个具有子节点的节点(内部节点,internal node)要么有两个子节点和一个数据元素,要么有三个子节点和两个数据元素的自平衡的树,它的所有叶子节点都具有相同的高度。

简单点讲,2-3树的非叶子节点都具有两个分叉或者三个分叉,所以,称作2叉-3叉树更容易理解。

另外一种说法,具有两个子节点和一个数据元素的节点又称作2节点,具有三个子节点和两个数据元素的节点又称作3节点,所以,整颗树叫做2-3树。
在这里插入图片描述

2-3树,插入元素后自平衡的过程相对于AVL树就要简单得多了,比如,上面这颗树,再插入一个元素K,它会先找到I J这个节点,插入元素K,形成临时节点I J K,不符合2-3树的规则,所以分裂,J往上移,F H这个节点变成了F H J了,也不符合2-3树的规则,继续上移H,根节点变为D H,同时,上移的过程中,子节点也要相应的分裂,过程大致如下:
在这里插入图片描述

可以看到,上面自平衡的过程中,出现了一种节点,它具有四个子节点和三个数据元素,这个节点可以称作4节点,如果把4节点当作是可以允许存在的,那么,就出现了另一种树:2-3-4树。

2-3-4树

2-3-4树,它的每个非叶子节点,要么是2节点,要么是3节点,要么是4节点,且可以自平衡,所以称作2-3-4树。

2节点、3节点、4节点的定义在上面已经提及,我们再重申一下:

2节点:包含两个子节点和一个数据元素;

3节点:包含三个子节点和两个数据元素;

4节点:包含四个子节点和三个数据元素;
在这里插入图片描述

当然,2-3-4树插入元素的过程也很好理解,比如,上面这颗树,插入元素M,找到K L这个节点,插入即可,形成4节点,满足规则,不需要自平衡:
在这里插入图片描述

再插入元素N呢?过程与2-3树一样,向上分裂即可,此时,中间节点有两个,取任意一个上移都是可以的,我们这里以左中节点上移为例,大致过程如下:
在这里插入图片描述

是不是挺简单的,至少比AVL树那种左旋右旋简单得多。

同样地,在2-3-4树自平衡的过程中出现了临时的5节点,所以,如果允许5节点的存在呢?

嗯,2-3-4-5树由此诞生!

同样地,还有2-3-4-5-6树、2-3-4-5-6-7树……子子孙孙,无穷尽也~

所以,有人就把这一类树归纳为一个新的名字:B树。

B树

B树,表示的是一类树,它允许一个节点可以有多于两个子节点,同时,也是自平衡的,叶子节点的高度都是相同的。

所以,为了更好地区分一颗B树到底属于哪一类树,我们给它一个新的属性:度(Degree)。

具有度为3的B树,表示一个节点最多有三个子节点,也就是2-3树的定义。

具有度为4的B树,表示一个节点最多有四个子节点,也就是2-3-4树的定义。
在这里插入图片描述

B树,一个节点可以存储多个元素,有利于缓存磁盘数据,整体的时间复杂度趋向于O(log n),原理也比较简单,所以,经常用于数据库的索引,包括早期的mysql也是使用B树来作为索引的。

但是,B树有个大缺陷,比如,我要按范围查找元素,以上面的2-3-4树为例,查找大于B且小于K的所有元素,该怎么实现呢?

很难,几乎无解,所以,后面又出现替代B树的方案:B+树。

当然了,B+树不是本节的重点,本节的重点是红黑树。

红黑树

先上一张图,请仔细体会:
在这里插入图片描述

看明白了没有?红黑树是啥?红黑树就是2-3-4树!!!

后记

从二叉树出发,一路经过二叉查找树、平衡树、AVL树、2-3树、2-3-4树、B树,最后终于得出了红黑树的本质,红黑树的本质就是一颗2-3-4树,换了个皮肤而已。

最后

感谢大家看到这里,文章有不足,欢迎大家指出;如果你觉得写得不错,那就给我一个赞吧。

也欢迎大家关注我的公众号:程序员麦冬,麦冬每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!