算法导论 - 红黑树及红黑树平衡的详细解析个人理解

算法导论 - 红黑树及红黑树平衡的详细解析个人理解

红黑树一种数据结构,效率极高,插入和删除的操作的时间复杂度都是logn,虽然红黑树对于前端来说基本很少用到,但是作为一个目标是全栈的程序员来说,算法的学习是很必要的,so … 图是"借的",字都是自己打的,也依据了自己的理解

数组 链表

数组特点是元素在内存中紧挨着存储,因而优点是定位快(O(1)),缺点是插入删除慢(O(n));而链表则不同,它通过指针将不同位置的元素链接起来,因而优缺点与数组正好相反:定位慢(O(n)),插入删除快(O(1))

排序二叉树

红黑树是特殊的排序二叉树,所以这里我们先介绍一下排序二叉树, 二叉树相较于二叉树具有以下特性,二叉树内的节点是不能重复的

  • 一个节点下只最多只有两个子节点

  • 节点的左子树都小于根节点的值

  • 节点的右子树都大于根节点的值
    在这里插入图片描述

排序二叉树的时间复杂度在完全平衡情况下为O(lgN),在极端情况下二叉树的时间复杂度为O(N),等于顺序排列的时间复杂度, 所以二叉树的时间复杂度在O(lgN)和O(N)之间,所以我们希望能构造一个比较平衡的二叉树, 这样效率比较稳定
在这里插入图片描述

二叉树的平衡与不平衡与插入的顺序有关

红黑树性质(R-B Tree)

HashMap, TreeMap, TreeSet

  1. 每节点都是红色或黑色

  2. 根节点是黑色

  3. 每个叶子节点(就是最末端的节点也就是null)是黑色(一般画图省略null)

  4. 如果一个节点是红色,那么它的两个子节点都是黑色(也就是说不能有两个相邻的红色节点)

  5. 从任一 节点开始到其所有子孙叶结点的路径中所包含的黑色结点数量必须相同。

在这里插入图片描述

红黑树 - 黑色高度

这里要阐明一个概念,从根节点到叶节点的包含的黑色节点的数量(不包括根节点)就是棵树的黑色高度, 例如上面这棵树的黑色高度就是

由此可知, 红黑树的任一节点到其叶节点的路径最长路径不超过最短路径的两倍,这就是相当于使用近似的平衡

简单的来说,就是能够保证二叉树的的每条分支的长度差不多

那如何保证的呢?!!

这里我们先来看一个图

在这里插入图片描述

可以发现同样的数据,可以用两种不同的二叉树来表示, 而这种操作就是红黑树用来平衡二叉树的方式 ,即左旋/右旋 , 当然还有变色

什么是左旋和右旋 (这里先说如何操作,再说什么时候使用)

在这里插入图片描述

左旋

在这里插入图片描述

右旋

因为相同元素的二叉树不是一个固定的结构,所每个节点都可以对他进行左旋右旋的操作,这样操作之后仍旧能保持二叉树的性质, 而红黑树让我们在插入和删除的过程中为了保证红黑的性质, 做左旋右旋或者变色的调整,从而保持红黑树的平衡

那么在插入和删除时我们是如何调整的呢!

插入

在插入之前,我们首先规定插入的节点颜色都为红色 ,因为(从任一 节点开始到其所有子孙叶结点的路径中所包含的黑色结点数量必须相同)这条规定,如果我们插入了黑色节点很容易就破坏了规定

下面我们想一下,在插入一个红色节点的时候会发生哪些情况,我们一一分析

  1. 插入的节点的位置为根节点, 直接涂黑就行了,根节点为黑色

  2. 插入位置父节点是一个黑色节点,显然这种情况我们不需要调整

  3. 插入的位置父节点是一个红色节点, 这时候就需要调整了,以为两个红色连在一起会违背规定4 ,这里分成三种情况

    • 插入位置为左键点, 父节点为红 , 叔叔节点为黑/nil的情况, 这是只需要进行一次左旋/右旋,然后将父节点变黑, 原来的爷爷节点变红,保证黑色数量不变

在这里插入图片描述

  • 插入位置为右键点, 父节点为红 , 叔叔节点为黑/nil的情况, 因为本节点比父节点大, 父节点作为子节点的左节点 ,这样和上面的情况就一样了不做赘述了

在这里插入图片描述

  • 父节点为红 , 叔叔节点为红,这时候爷爷节点必是黑,这时候很简单直接把父亲和叔叔变黑,爷爷节点变红就行了,这时候万一爷爷的爸爸也是红怎么办, 这时候我们就把爷爷节点当做一个新插入的节点做同样操作就行了

在这里插入图片描述

删除

一个节点前驱后继

在了解删除之前,我们首先需要知道的的是一个节点的前驱和后继是什么 , 简单来说就是离这个节点数字最近的两个数字节点

在这里插入图片描述

这里举个例子,以17为例子,他的前驱就是16后驱就是19

这时我们需要删除17这个节点,就可以把他的前驱或者后继放到他的位置上来位置二叉树结构, 这样就相当于我们只是删除了前驱(后继)上的节点, 这有什么用呢,因为前驱和后继的情况比较简单,前驱只能有左节点,后继只能有右节点,当前驱和后继被当成替死鬼之后, 子节点直接被当成备胎提来

这里为了方便解释,我们将删除后新生成的树的各个角色标记

  • N就是那个备胎
  • P是父节点
  • S是兄弟节点
  • SL是左侄子节点
  • SR是右侄子节点
  • X没有标记就是被删除的节点,原来在N的位置
    在这里插入图片描述

这里我们也将删除分成几种情况

  • 被删除的节点是红色, 不需要平衡不影响黑色数量

  • N节点为红色,只要直接变成红色就好了

  • 被删除的节点是黑色,N也是黑色(下面可以分为这几种)

    1. 所有节点都为黑色

在这里插入图片描述

 **操作:  直接将S变成红色,这时P节点下的整个树都比其他分支少一个黑色节点,这时我们把P看成一个新的N节点来处理,向上重新来平衡树**

在这里插入图片描述

  1. P节点为红, 其他都为黑

在这里插入图片描述

 **操作: 将P变成黑,S变成红, 这时经过S的分支数量没有变化, N这边刚好多了一个平衡了**

在这里插入图片描述

  1. 节点和SL节点颜色不重要, N,S为黑, SR为红

在这里插入图片描述

 **操作: 以P左旋,P和S颜色互换,SR改为黑色,经过N的多了一个P, 经过SL的不变,SR因为自己变黑了所以也不变**

在这里插入图片描述

  1. P节点颜色不重要,SL为红,SR为黑,因为上面的以及讨论过SR为红的情况了

在这里插入图片描述

 **操作: 以S节点右旋转,交换S和SL颜色, 这样的旋转不会改变S各分支的黑色数量,这时由于SL原来是红色,所以他的左子节点必定是黑色, 所以我们可以发现这种情况与上面的情况4相同,按照上面的方法来平衡**

在这里插入图片描述

  1. S节点事红色,其他节点都是黑色

在这里插入图片描述

 **操作: 以P为点,左旋转, 交换P和S的颜色, 这是N所处的情况就是P为红,兄弟为黑的情况了,可以参照2,3,4具体情况处理**

在这里插入图片描述

到这里所以平衡的情况都处理完了!!!

总结

​ 总的来说红黑树就是通过旋转变色,来维持整个红黑二叉树的平衡,最终保证不管添加了多少各节点, 最长分支不会超过最短分支的两倍长度,这样能保证每次操作的效率都是比较稳定的 .

​ 但是这种树并不是非常平衡,当然还存在一种AVL树, 是一种完全平衡树, 分支之间节点数量不能差超过一个节点,但是这样势必会增加平衡的操作,得不偿失. 红黑树的插入平衡次数最多两次, 删除最多平衡三次 , AVl树插入删除的复杂度都是log(N),但是在查询是效率是要高于红黑树的

​ 说了这么多红黑树的平衡,其实讲道理基本看的时候理解了,到这里忽然有失忆了,我觉得学习红黑树并不是要背下来是如何处理的,是要去了解平衡过程中的思路,顺带膜拜膜拜大佬们的思想,到底是怎么想出这个东西的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章