数据结构与算法:红黑树(二)——数据操作

红黑树(一)——数据操作


0. 前言

  上篇文章中(数据结构与算法:红黑树(一)——基本概念),主要介绍了红黑树的基本概念。
  本篇文章对红黑树的数据操作进行详细讲解。
  为了方便讲解,这里讲红黑树的特性写在这里。

  1. 每个节点或是黑色或是红色
  2. 根节点是黑色
  3. 每个叶节点是黑色(叶节点为空节点)
  4. 如果一个节点是红色,则它的子节点必须是黑色
  5. 从一个节点到该节点的所有叶节点的路径包含相同数目的黑色节点

1. 查找

  红黑树的查找方式很简单,是一个递归过程。如果查找的元素小于当前节点,那么查找其左子树;如果查找的元素大于当前元素,则查找其右子树。查找的时间复杂度为 O ( log 2 n )


2. 插入

(图例:C表示当前节点,P表示父节点,U表示叔节点,G表示祖父节点)

  插入操作首先需要通过查找操作找到合适的插入点,然后插入新节点。如果在插入节点后,发生了违背红黑树特性的情况时,需要对红黑树进行旋转染色等操作,使其重新满足特性。

2.1 插入新节点

  为了在插入新节点时尽可能少的违反红黑树特性且更容易调整红黑树,就先将新节点染成红色。这样就只可能会违法特性4。如果这里没有违反特性4,那么就不需要对红黑树进行调整,插入操作完成。

2.2 调整子树

  那么,在违反了特性4的时候,新节点的父节点为红色节点。根据特性2可知,父节点不是根节点,则新节点必有祖父节点。
  又根据特性3可推论出红色节点必有两个黑色子节点(空节点为黑色)
  此时会出现两种情况:叔节点为红色、叔节点为黑色。
  
(1)父节点与叔节点都为红色的情况
情况1
  在这种情况下,需要将父节点和叔节点变为黑色,再将祖父节点变为红色。这样,图上所展示的子树就满足了红黑树的特性。如下图所示。
调整后1
  但是这里又可能会产生新的违法特性情况,因为祖父节点变成了红色,那么它可能会造成违反特性4的情况。所以,这里就将祖父节点作为当前节点,进行新一轮的调整操作。

(2)父节点为红色叔节点为黑色的情况
情况2
  在这种情况下,对其调整的核心就是保持父节点分支符合特性4,而叔节点分支保持符合特性5。
  第一步,旋转。对祖父节点进行左旋或者右旋。如果父节点是祖父节点的右子节点,那么对祖父节点进行左旋;否则,对祖父节点进行右旋。
  第二步,染色。将祖父节点染为红色,而父节点染为黑色。
  进过这两步,上图的情况会转换为下图所示。
调整后2
  可以看出,父节点这一分支进过调整后,当前节点与父节点的颜色不再是连续红色,满足特性4。而叔节点这一分支的黑色节点数目没有发生变化,满足特性5。
  对原祖父节点的父节点来说,该子树没有发生违反特性的变化。该子树调整完成。

2.3 检查根节点

  当上述调整执行完后,还有最后一步,就是检查是否满足特性2。这一步只需要将根节点染成黑色就可以,无需再多加判断。


3. 删除

(图例:D表示当前节点,P表示父节点,B表示兄弟节点,BR表示兄弟节点的右子节点,BL表示兄弟节点的左子节点)

  删除操作要比插入操作略微复杂一些。因为删除的节点可能是出现在树的中间层的节点,此时删除该节点会遇到很复杂的情况。所以,在删除节点的时候,需要先对红黑树进行一些调整,使得删除节点对整个树的影响降到最低。

3.1 替换删除节点

  首先根据BST删除节点的规则,使用当前节点左子树的最大值节点或者右子树的最小值节点代替其删除(这两个节点是其子树中数值上最贴近当前节点数值的节点)。
节点删除替换
  为了方便讲解,我们默认采用的是右子树的最小值节点代替。

public void findSuccessor(Entry p) {
    // 右子树的根节点
    Entry s = p.right;
    // 寻找右子树的最小值节点
    while (s != null) {
        s = s.left;
    }
    // 替换
    p.value = s.value;
    p = s;
}

  那么现在需要考虑的情况就减少了,只可能会出现以下几种情况(因为需要满足红黑树特性):
  1. 无子节点,节点为红色
  2. 无子节点,节点为黑色
  3. 只有右子节点,右子节点为红色,节点本身为黑色
待删除节点
  情况1,只需要直接删除节点就可以。
  情况2,删除节点后,违反了红黑树特性5,需要调整(不考虑待删除节点为根节点的情况)
  情况3,用右子节点占据待删除节点,再将其染成黑色即可,不违反红黑树特性。
 
  在这三种情况中,情况1和情况3比较简单,不需要多余的调整。情况2则需要后续的调整步骤使其满足红黑树特性。

3.2 调整红黑树

  上述情况2的调整比较复杂。下面对各种情况进行讲解。
  根据红黑树的特性5,待删除节点必然有兄弟节点。下面根据其兄弟节点所在分支的不同,来分情况讨论。
  (以下是以关注节点为父节点的左子节点进行描述,如果遇到关注节点为父节点的右子节点的情况,则镜像处理)
(1)兄弟节点为红色

  先对父节点进行左旋操作,然后将父节点染成红色,兄弟节点染成黑色。此时就转换为了(4),之后按照(4)继续进行调整。

(2)兄弟节点为黑色,远侄节点为红色

  这种情况下,不需要考虑父节点的颜色。
  第一步:对父节点P进行左旋操作
  第二步:将父节点P与兄弟节点B的颜色互换
  第三步:将兄弟节点的右子节点BR染成黑色
  可以看到,经过这三步的调整后,直接删除节点D后满足红黑树的特性,调整完成。

(3)兄弟节点为黑色,远侄节点为黑色,近侄节点为红色

  这种情况下,先对兄弟节点B进行右旋操作,然后BL节点染成黑色,B节点染成红色。此时的状况就和(2)一样了。之后就通过(2)的调整方式进行调整。

(4)父节点为红色,兄弟节点为黑色,兄弟节点无子节点

  这种情况下,将父节点P染成黑色,再将兄弟节点染成红色。
  经过这样的操作后,除去节点D后,以P为根节点的子树的黑节点深度没有发生。调整完成。

(5)父节点为黑色,兄弟节点为黑色,兄弟节点无子节点

  这种情况下,为了在删除节点D后使以P为根节点的子树能满足红黑树特性5,将兄弟节点B染成红色。但是这样操作后,以P为根节点的子树的黑色节点深度变小了。所以需要继续调整。
  因为P节点子树的黑色深度发生了减少,可以把其当作待删除节点,那么此时就以P节点为关注节点进行进一步调整。
  

3.3 检查根节点及删除节点

  经过上述的调整后,此时基本满足了红黑树的特性。但是存在根节点变成红色的情况。所以需要将根节点染成黑色的操作。
  最后,执行删除操作,将待删除节点删掉。


4. 总结

  本篇文章讲解了红黑树的数据操作,包括查找、插入和删除三种操作。

发布了21 篇原创文章 · 获赞 63 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/dongzhong1990/article/details/80789668