了解红黑树的起源,理解红黑树的本质

前言

本文收录于专辑:http://dwz.win/HjK,点击解锁更多数据结构与算法的知识。node

你好,我是彤哥。mysql

前面两节,咱们一块儿学习了关于跳表的理论知识,并手写了两种彻底不一样的实现,咱们放一张图来简单地回顾一下:程序员

15

实现跳表的关键之处是在有序链表的基础上加上各层索引,经过这些索引能够作到O(log n)的时间复杂度快速地插入、删除、查找元素。面试

提及跳表,咱们就不得不提另外一种很是经典的数据结构——红黑树,红黑树相对于跳表来讲,虽然时间复杂度都是O(log n),可是红黑树的使用场景相对更普遍一些,在早期的Linux内核中就一直存在红黑树的实现,也运用在了更高效的多路复用器Epoll中。算法

因此,红黑树是每个程序员不得不会的知识点,甚至有些变态的面试官,还会让你手写红黑树的一部分实现,好比左旋、右旋、插入平衡的过程、删除平衡的过程,这些内容很是复杂,靠死记硬背每每很难完全掌握。sql

彤哥也是一直在寻找一种红黑树的记忆法,总算让我找到了那么一种还算不错的方式,从红黑树的起源出发,理解红黑树的本质,再从本质出发,完全掌握不用死记硬背的方法,最后再把它手写出来。数据库

从本节开始,我也将把这种方法传递给你,所以,红黑树的部分,我会分红三个小节来说解:缓存

  • 从红黑树的起源,到红黑树的本质
  • 从红黑树的本质,找到不用死记硬背的方法
  • 不靠死记硬背,手写红黑树

好了,下面咱们就进入第一小节。数据结构

红黑树的起源

二叉树

提及树,咱们不得不说最有名的树,那就是二叉树,什么是二叉树呢?架构

二叉树(binary tree),是指树中的每一个节点最多只有两个子节点的树。

1

固然,二叉树自己彷佛没什么用,咱们平时说的二叉树基本上都是指二叉查找树,或者叫有序二叉树、二叉搜索树、二叉排序树。

二叉查找树

二叉查找树(BST,binary search tree),就是在二叉树的基础上增长有序性,这个有序性通常是指天然顺序,有了有序性,咱们就可使用二叉树来快速的查找、删除、插入元素了。

2

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

可是,二叉查找树有个很是严重的问题,试想,仍是这三个元素,若是按照A、B、C的顺序插入元素会怎样?

3

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

因此,在极限状况下,二叉查找树的时间复杂度是很是差的。

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

答案是确定的,这种手段就叫作平衡,这种能够自平衡的树就叫作平衡树。

平衡树

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

好比,上面那颗树,按A、B、C插入元素后,作一次旋转操做,就能够再次变成查找时间复杂度为O(log n)的树。

4

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

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

AVL树

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

5

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

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

第二个缺点,就是插入、删除元素的时候自平衡的过程很是复杂,好比,上面这颗树插入一个节点T

6

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

我下面给出图示,你能够试着理解一下:

7

红色节点表示旋转的轴。

通过两次旋转,让这颗树再次变成了AVL树,并且这只是其中一种插入场景,真实的状况还要根据插入的位置的不一样作不一样的旋转,你能够多插入几个节点本身尝试平衡一下。

一样地,AVL树的代码也不是那么好实现的,反正,到目前为止,彤哥是没搞懂AVL树的各类规则。

基于这些缺点,因此,后来又发展出来了各类各样的神奇的平衡树。

2-3树

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

简单点讲,2-3树的非叶子节点都具备两个分叉或者三个分叉,因此,称做2叉-3叉树更容易理解。

另一种说法,具备两个子节点和一个数据元素的节点又称做2节点,具备三个子节点和两个数据元素的节点又称做3节点,因此,整颗树叫作2-3树。

8

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

9

画图辛苦了,关注一波:彤哥读源码。

能够看到,上面自平衡的过程当中,出现了一种节点,它具备四个子节点和三个数据元素,这个节点能够称做4节点,若是把4节点看成是能够容许存在的,那么,就出现了另外一种树:2-3-4树。

2-3-4树

2-3-4树,它的每一个非叶子节点,要么是2节点,要么是3节点,要么是4节点,且能够自平衡,因此称做2-3-4树。

2节点、3节点、4节点的定义在上面已经说起,咱们再重申一下:

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

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

4节点:包含四个子节点和三个数据元素;

10

固然,2-3-4树插入元素的过程也很好理解,好比,上面这颗树,插入元素M,找到K L这个节点,插入便可,造成4节点,知足规则,不须要自平衡:

11

再插入元素N呢?过程与2-3树同样,向上分裂便可,此时,中间节点有两个,取任意一个上移都是能够的,咱们这里以左中节点上移为例,大体过程以下:

12

是否是挺简单的,至少比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树的定义。

13

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

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

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

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

纳尼,红黑树在哪里?写了3000多字了,还没见到红黑树的影子,我尬了~

来了来了,有意思的红黑树来了~~

红黑树

先上一张图,请仔细体会:

14

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

OK,本节到此结束。

后记

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

那么,为何要再造一个红黑树呢?直接用2-3-4树它不香么?

咱们下一节解答,同时,下一节,咱们将从红黑树的本质出发,完全理解红黑树插入、删除、查找、左旋、右旋的全过程,不再用死记硬背了,还不来关注我^^

关注公主号“彤哥读源码”,解锁更多源码、基础、架构知识。