动画演示!红黑树解析

红黑树动图解析

一、啥是红黑树?

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。因此想要弄清楚红黑树,我们需要先解决几个问题:

  • 二叉查找树是什么?
  • 为什么会出现红黑树?

二、剖析二叉查找树

二叉查找树特性

二叉查找树(Binary Search Tree)是一颗二叉树,简称BST。就像我们说int都是整数一样,BST这一种二叉树需要满足如下三个特性:

  • 某节点的左子树节点值仅包含小于该节点值
  • 某节点的右子树节点值仅包含大于该节点值
  • 左右子树每个也必须是二叉查找树
长啥样?

在线演示BST网址:https://www.cs.usfca.edu/~galles/visualization/BST.html

ps:这个网站不只二叉树,绝大部分算法的增删改查都可以去演示,是理解算法的好帮手,强烈建议保存!

BST在理想情况下是如下这样的:

BST理想状态

当BST发生倾斜后是这样的:

发生倾斜的BST演示
在理想的情况下,二叉查找树增删查改的时间复杂度为O(logN)(其中N为节点数),最坏的情况下为O(N)

怎么解决倾斜

通过以上两个相同数据的BST的演示,我们发现了一个问题,同样的数据组成,只是因为数据插入的先后顺序,就使得产生的二叉查找树发生了倾斜
那么我们怎么解决这个问题呢?首先想到的就是每次插入或者删除数据的时候都进行判断,对已经存在的树结构进行旋转,使其维持在logN的高度上,这样不管我们按照什么样的顺序插入数据,最终的结构只要能满足logN的高度,那它的结构一定是理想状态下的。

红黑树产生

基于BST存在的问题,一种新的树——平衡二叉查找树(Balanced BST)产生了。平衡树在插入和删除的时候,会通过旋转操作将高度保持在logN。其中两款具有代表性的平衡树分别为AVL树和红黑树。AVL树由于实现比较复杂,而且插入和删除性能差,因此在实际环境中我们更多的是应用红黑树。

三、红黑树的用途及特性

用途

红黑树(Red-Black Tree)以下简称RBTree的实际应用非常广泛,比如Linux内核中的完全公平调度器、高精度计时器、ext3文件系统等等,各种语言的函数库如Java的TreeMap和TreeSet,C++ STL的map、multimap、multiset等,是函数式语言中最常用的持久数据结构之一。
由于在java8里HashMap的底层实现用RBTree取代链表,使得性能得到了提升,因此很多人才去关注或者深入学习红黑树。

特性

RBT树上的每个节点,都要遵循下面的规则:

  1. 每个节点都是红色或者黑色;
  2. 根节点必须始终是黑色;
  3. 没有两个相邻的红色节点;
  4. 对每个结点,从该结点到其子孙节点的所有路径上包含相同数目的黑结点。

RBT树在理论上还是一棵BST树,但是它在对BST的插入和删除操作时会维持树的平衡,即保证树的高度在[logN,logN+1](理论上,极端的情况下可以出现RBTree的高度达到2*logN,但实际上很难遇到)。这样RBTree的查找时间复杂度始终保持在O(logN)从而接近于理想的BST。RBTree的删除和插入操作的时间复杂度也是O(logN)。RBT的查找操作就是BST的查找操作。
上面的规则看一下有个印象就好,接下来是红黑树比较复杂的地方,就是红黑树的调整,
为了达到这一目的,

四、拒绝死记硬背,跟着动图理解调整算法

为了维持RBT的规则,RBT定义了两个重要的操作:

  1. rotation:旋转,这是树达到平衡的关键;
  2. recolor :重新标记黑色或红色。
4.1、 首先先看最基础的recolor,也就是第一种情况

先看如下gif:
RBT recolor演示

小结一波:

通过上面动图,我们发现整个插入及调整一共是如下7步:

  1. 新插入的节点004标记为红色;
  2. 插入后发现004的父节点005也是红色,违反了RBT的规则3( 没有两个相邻的红色节点);
  3. 发现004的叔父节点007同样是红色;
  4. 使用recolor方法,把005和007也就是父节点和叔父节点标记为黑色;
  5. 将004和它的祖父节点006标记为相同的颜色,也就是红色,往上递归重复步骤2,3;
  6. 发现它的祖父节点是根节点,标记为黑色;
  7. 调整完毕。
4.2、开始考虑旋转rotation方法,首先展示第二种情况:左旋

先看如下gif:
rotation之左旋

小结一波:

这里我们就不用再分步骤去看了,只需要知道整体的调整方式就行了;左旋就是当新加入节点之后,树的高度及颜色不再满足RBT定义的规则后;将不满足的节点进行左旋转,使得它取代之前它的父节点,同时它的父节点变为它的左子节点,最后应用第一种方法调整颜色的过程。

4.3、第三种情况:右旋

先看如下gif:
rotation之右旋

小结一波:

右旋就是以某节点为中心进行向右的旋转,取代并成为之前自己的父节点,然后把之前的父节点变为自己的右子节点,最后应用第一种方法调整颜色的过程。

五、总结

最后我们把实际使用中,或者研究HashMap源码时需要提前了解的红黑树调整规则整理总结一下:
为了方便记忆,我们取英文首字母,定义连续的三代节点,新增节点为N,父节点为P,叔父节点为U,祖父节点为G

情况 处理方式
N和U都是红色 将P和U修改为黑色,G修改为红色
N是P的左节点,同时U是黑色 对G进行一次右旋转,然后根据规则调整颜色
N是P的右节点,同时U是黑色 首先对P进行一次左旋转,然后套用上一种调整情况

红黑树看似复杂,其实只要我们理解了它的来源,定义的规则,为了完成规则使用的方法及三种调整策略,然后多加练习,多观察,就可以很容易的去掌握它的规律。

猜你喜欢

转载自blog.csdn.net/qq_26803795/article/details/106258368