第十四章 红黑树

文章目录

  • 第十四章 红黑树
  • 一、红黑树
    • 1.介绍
    • 2.插入结点
    • 3.删除结点
    • 4.与平衡二叉树的对比

一、红黑树

1.介绍

红黑树(Red Black Tree)是平衡二叉树的其中一种实现方式,解决了二叉排序树多次插入新结点导致的不平衡问题

除了二叉排序树的基本特性外,它还具有下列附加规则:

  1. 结点是红色或黑色
  2. 根结点是黑色
  3. 每个叶子结点都是黑色的空结点(NIL 结点)
  4. 每个红色结点的两个子结点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色结点)
  5. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点
  6. 平衡二叉树是严格平衡的二叉树,要求每个结点的左右子树高度差不超过 1。而红黑树则要宽松一些,只要求任何一条路径的长度不超过其他路径长度的 2 倍

当插入或删除结点的时候,红黑树的规则可能被打破。这时候就需要做出一些调整,从而继续维持我们的规则

向原红黑树插入值为 14 的新结点

由于父结点 15 是黑色结点,因此这种情况并不会破坏红黑树的规则,无需做任何调整

向原红黑树插入值为 21 的新结点

由于父结点 22 是红色结点,因此这种情况打破了红黑树的规则 4(每个红色结点的两个子结点都是黑色),必须进行调整,使之重新符合红黑树的规则

调整的方法有变色和旋转,和常规的平衡二叉树一样,旋转包含左旋转和右旋转

变色:

为了重新符合红黑树的规则,尝试把红色结点变为黑色,或者把黑色结点变为红色

下图所表示的是红黑树的一部分(子树),新插入的结点 Y 是红色结点,它的父结点 X 也是红色的,不符合规则 4,因此我们可以把结点 X 从红色变为黑色

但是,仅仅把一个结点变色,会导致相关路径凭空多出一个黑色结点,这样就打破了规则 5。因此,我们需要对其它结点做进一步的调整,后文会详细说明

2.插入结点

红黑树插入新结点的时候可以分为 5 种不同的局面,每一种局面有不同的调整方案

局面 1:新结点(A)位于树根,没有父结点

空心三角形代表结点下面的子树

这种局面,直接让新结点变色为黑色,规则 2 得到满足。同时,黑色的根结点使得每条路径上的黑色结点数目都增加了 1,所以并没有打破规则 5

局面 2:新结点(B)的父结点是黑色

这种局面,新插入的红色结点 B 并没有打破红黑树的规则,所以不需要做任何调整

局面 3:新结点(D)的父结点和叔叔结点都是红色

这种局面,两个红色结点 B 和 D 连续,违反了规则 4,因此我们先让结点 B 变为黑色

这样一来,结点 B 所在路径凭空多了一个黑色结点,打破了规则 5,因此我们让结点 A 变为红色:

这时候,结点 A 和 C 又成为了连续的红色结点,我们再让结点 C 变为黑色

经过上面的调整,这一局部重新符合了红黑树的规则

局面 4:新结点(D)的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右子结点,父结点(B)是祖父结点的左子结点

我们以结点 B 为轴,做一次左旋转,使得新结点 D 成为父结点,原来的父结点 B 称为 D 的左子结点

这样一来,进入了局面 5

局面 5:新结点(D)的父结点是红色, 叔叔结点是黑色或者没有叔叔,且新结点是父结点的左子结点,父结点(B)是祖父结点的左子结点

我们以结点 A 为轴,做一次右旋转,使得结点 B 成为祖父结点,结点 A 成为结点 B 的右子结点:

接下来,我们让结点 B 变为黑色,结点 A 变为红色

经过上面的调整,这一局部重新符合了红黑树的规则

如果局面 4 中的父结点(B)是右子结点,则成为了局面 5 的镜像,原本的右旋转改为左旋转

如果局面 5 中的父结点(B)是右子结点,则成为了局面 4 的镜像,原本的左旋转改为右旋转

我们不用刻意记住这些局面的处理方式,只需要有个大概了解即可

实例演示:

给定下面这棵红黑树,新插入的结点是 21

显然,新结点 21 和它的父结点 22 是连续的红色结点,违背了规则 4,我们应该如何调整呢?

让我们回顾一下刚才讲的 5 种局面,当前的情况符合局面 3:新结点的父结点和叔叔结点都是红色

于是我们经过三次变色,22 变为黑色,25 变为红色,27 变为黑色

经过上面的调整,以结点 25 为根的子树符合了红黑树规则,但结点 25 和结点 17 成为了连续的红色结点,违背了规则 4

于是,我们把结点 25 看作一个新结点,正好符合局面 5 的镜像:新结点的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右子结点,父结点是祖父结点的右子结点

于是我们以根结点 14 为轴进行左旋转,使得结点 17 成为了新的根结点

接下来,让结点 17 变为黑色,结点 13 变为红色

如此一来,我们的红黑树变得重新符合规则

3.删除结点

第一步:如果待删除结点有两个非空的子结点,转化成待删除结点只有一个子结点(或者没有子结点)的情况

上面的例子是一棵红黑树的局部,标数字的三角形代表任意形态的子树,假设结点 8 是待删除结点

根据上文讲解的二叉查找树的删除流程,由于结点 8 有两个子结点,我们选择仅大于 8 的结点 10 复制到 8 的位置,结点颜色变成待删除结点的颜色

接下来我们需要删除红色的结点 10

红色结点 10 能成为仅大于 8 的结点,必定没有左子结点,所以问题转换成了待删除结点只有一个右子结点(或没有子结点)的情况,接下来我们进入第二步

第二步:根据待删除结点和其唯一子结点的颜色,分情况处理

情况 1,自身是红色,子结点是黑色

这种情况最简单,按照二叉排序树的删除操作,删除结点 1 即可

情况 2,自身是黑色,子结点是红色:

这种情况也很简单,首先按照二叉查找树的删除操作,删除结点 1

此时,这条路径凭空减少了一个黑色结点,那么我们需要再把结点 2 变成黑色

情况 3,自身是黑色,子结点也是黑色,或者子结点是空叶子结点

这种情况最复杂,涉及到很多变化。首先我们还是按照二叉排序树的删除操作,删除结点 1

显然,这条路径上减少了一个黑色结点,而且结点 2 再怎么变色也解决不了

这时候我们进入第三步,专门解决父子双黑的情况

第三步:遇到双黑结点,在子结点顶替父结点之后,分成 6 种情况处理

情况 1,结点 2 是红黑树的根结点:

此时所有路径都减少了一个黑色结点,并未打破规则,不需要调整

情况 2,结点 2 的父亲、兄弟、侄子结点都是黑色

此时,我们直接把结点 2 的兄弟结点 B 改为红色

这样一来,原本结点 2 所在的路径少了一个黑色结点,现在结点 B 所在的路径也少了一个黑色结点,两边“扯平”了

可是,结点 A 以下的每一条路径都减少了一个黑色结点,与结点 A 之外的其它路径又造成了新的不平衡呢?

没关系,我们让结点 A 扮演原先结点 2 的角色,进行递归操作,重新判断各种情况

情况 3,结点2的兄弟结点是红色

首先以结点 2 的父结点 A 为轴,进行左旋转

然后将结点 A 变成红色、结点 B 变成黑色

这样的意义是什么呢?结点 2 所在的路径仍然少一个黑色结点呀?

别急,这样的变化有可能转换成情况 4、5、6 中的任意一种,在情况 4、5、6 当中会进一步解决

情况 4,结点 2 的父结点是红色,兄弟和侄子结点是黑色

这种情况,我们直接让结点 2 的父结点 A 变成黑色,兄弟结点 B 变成红色

这样一来,结点 2 的路径补充了黑色结点,而结点 B 的路径并没有减少黑色结点,重新符合了红黑树的规则

情况 5,结点 2 的父结点随意,兄弟结点 B 是黑色右子结点,左侄子结点是红色,右侄子结点是黑色

这种情况下,首先以结点 2 的兄弟结点 B 为轴进行右旋转

接下来结点 B 变为红色,结点 C 变为黑色

这样的变化转换成了情况 6

情况 6,结点 2 的父结点随意,兄弟结点 B 是黑色右子结点,右侄子结点是红色

首先以结点 2 的父结点 A 为轴左旋转

接下来让结点 A 和结点 B 的颜色交换,并且结点 D 变为黑色

经过结点 2 的路径由(随意+黑)变成了(随意+黑+黑),补充了一个黑色结点

经过结点 D 的路径由(随意+黑+红)变成了(随意+黑),黑色结点并没有减少

所以,这时候重新符合了红黑树的规则

实例演示:

给定下面这棵红黑树,待删除的是结点 17

第一步,由于结点 17 有两个子结点,子树当中仅大于 17 的结点是 25,所以把结点 25 复制到 17 位置,保持黑色

接下来,我们需要删除原本的结点 25

这个情况正好对应于第二步的情况三,即待删除结点是黑色,子结点是空叶子结点

于是我们删除框框中结点 25,进入第三步

此时,框框中的结点虽然是空叶子结点,但仍然可以用于判断局面,当前局面符合情况 5 的镜像

于是我们通过左旋和变色,把子树转换成情况 6 的镜像

再经过右旋和变色,子树最终成为了下面的样子

这样一来,整棵二叉树又重新符合了红黑树的规则

4.与平衡二叉树的对比

平衡二叉树是严格平衡的二叉树,要求每个结点的左右子树高度差不超过 1。而红黑树则要宽松一些,只要求任何一条路径的长度不超过其他路径长度的 2 倍

正因为这个差别,二叉平衡树的查找效率更高,但平衡调整的成本也更高,在需要频繁查找时,选用二叉平衡树更合适,在需要频繁插入删除时,选用红黑树更合适

【Java数据结构与算法】第十四章 红黑树相关推荐

  1. Java数据结构与算法(第四章栈和队列)

    2019独角兽企业重金招聘Python工程师标准>>> 本章涉及的三种数据存储类型:栈.队列和优先级队列. 不同类型的结构 程序员的工具 数组是已经介绍过的数据存储结构,和其他结构( ...

  2. 【Java数据结构与算法】第四章 栈实现综合计算器

    第四章 栈实现综合计算器 文章目录 第四章 栈实现综合计算器 一.栈 1.介绍 2.应用场景 3.思路 4.代码实现 二.综合计算器 v1.0 1.思路 2.代码实现 三.前缀.中缀和后缀表达式规则 ...

  3. 14_JavaScript数据结构与算法(十四)图

    JavaScript 数据结构与算法(十四)图 图的概念 在计算机程序设计中,图也是一种非常常见的数据结构,图论其实是一个非常大的话题,在数学上起源于哥尼斯堡七桥问题. 什么是图? 图是一种与树有些相 ...

  4. Java 数据结构和算法(十五):无权无向图

    Java数据结构和算法(十五)--无权无向图 前面我们介绍了树这种数据结构,树是由n(n>0)个有限节点通过连接它们的边组成一个具有层次关系的集合,把它叫做"树"是因为它看起 ...

  5. 斗地主AI算法——第十四章の主动出牌(3)

    上一章已经排除了飞机.三带等牌型,那么除去炸弹王炸以外,我们只剩下单牌.对牌.三牌以及单顺.双顺.三顺了. 首先说单牌.对牌.三牌.其逻辑基本一样,只是出牌的个数有差别,即:如果该i牌数量满足这种牌型 ...

  6. Java数据结构和算法(十)——二叉树

    接下来我们将会介绍另外一种数据结构--树.二叉树是树这种数据结构的一员,后面我们还会介绍红黑树,2-3-4树等数据结构.那么为什么要使用树?它有什么优点? 前面我们介绍数组的数据结构,我们知道对于有序 ...

  7. 《学习JavaScript数据结构与算法》 第四章笔记 栈

    文章目录 前言 一.栈? 二.构建两种栈的大致步骤 三.创建基于数组的栈 创建class Stack 定义用于操作栈的方法 使用栈 四.创建基于对象的栈 创建class Stack 定义用于操作栈的方 ...

  8. Android版数据结构与算法汇总十二章

    Android版数据结构与算法(一):基础简介 https://www.cnblogs.com/leipDao/p/9140726.html Android版数据结构与算法(二):基于数组的实现Arr ...

  9. 算法导论第十三章 红黑树

    写在前面:这一章真的把我害惨了,之前至少尝试看过3遍,每次看之前都下定决定一定要把它拿下,可是由于内容较多,深度够深,以致于每次要不是中途有什么事放弃了就跳过了,要不是花时间太多仍然不能理解而放弃.这 ...

最新文章

  1. 【JS第28期】继承-借用构造函数
  2. Java学习笔记30
  3. RabbitMQ 一二事 - 简单队列使用
  4. 单片机汇编编程300例_pic单片机编程串烧,pic单片机汇编语言讲解下篇
  5. 我的Go语言学习之旅一:WIN下Go的安装
  6. html 两个表合并,SQL中将两个表合并成一个新表
  7. pcd格式点云的显示程序
  8. win10电脑装USB CAN 1报错代码39
  9. Win10 C盘修改用户文件夹
  10. 上原れな - 届かない恋
  11. cadence一些快捷键
  12. 哈工大计算机系统大作业:程序人生-Hello’s P2P
  13. [题单]多校补题 2017-2012
  14. echarts的词云图
  15. JAVA中下载文件名含有中文乱码一种少见的解决方案
  16. [C++] 获取IE代理服务器的账号密码
  17. python http服务器
  18. 新学期新环境学习计划
  19. html一行字不同颜色6,html语言的字体设置
  20. pycharm踩坑指南

热门文章

  1. 包含几通道数据_功率分析仪和数据采集记录仪有什么区别?
  2. leetcode 61. Rotate List
  3. Oracle安装-------实例化EM 配置文件时出错问题 ( 转 )
  4. 软件需求和问题解决-转载
  5. 用xib自定义UIView并在代码中使用--iOS
  6. 输入框聚焦隐藏提示语
  7. Client访问Tomcat简单流程(Struts2)
  8. ASP.NET实现多域名多网站共享Session值
  9. python安装 pip_多版本Python安装pip及pip版本管理终极教程
  10. eclipse编辑器未包含main类型_Shopify模版编辑器问题排查及解决办法汇总