红黑树脑图

目录

文章目录

  • 红黑树的定义
  • 四点特征
  • 为什么红黑树是近似平衡的
    • (1)首先,我们来看,如果我们将红色节点从红黑树中去掉,那单纯包含黑色节点的红黑树的高度是多少呢?
    • (2)现在把红色节点加回去,高度会变成多少呢?
  • 基本思想
    • 旋转
    • 插入
    • 删除
  • 应用

二叉查找树由于在频繁的动态更新过程中,可能会出现树的高度远大于 log2n的情况,所以就会导致各个操作效率下降,最坏的情况下就会退化为链表,变为O(n).很明显,想要解决这个问题,有效的一种办法就是使得树的高度不要差很多,也就是平衡它.

最先发明的平衡二叉查找树是AVL树,(它严格符合平衡二叉查找树的定义,即任何节点的左右子树高度相差不超过 1,是一种高度平衡的二叉查找树。)但是在工程中,我们经常听到的通常是红黑树,而不是AVL树.那么为什么工程中都喜欢用红黑树,而不是其他平衡二叉查找树呢?

平衡二叉树是严格按照规定执行,每次的插入,删除,都就会引发树的调整.调整的多了,自然会影响树的效率.那么红黑树又是怎样解决这个问题的呐?

其实,平衡二叉查找树中“平衡”的意思,其实就是让整棵树左右看起来比较“对称”、比较“平衡”,不要出现左子树很高、右子树很矮的情况。这样就能让整棵树的高度相对来说低一些,相应的插入、删除、查找等操作的效率高一些。

红黑树的定义

红黑树的英文是“Red-Black Tree”,简称 R-B Tree。它是一种不严格的平衡二叉查找树.
顾名思义,红黑树中的节点,一类被标记为黑色,一类被标记为红色

四点特征

  1. 根节点是黑色的;
  2. 每个叶子节点都是黑色的空节点,也就是说,叶子节点不存储数据;
  3. 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的;
  4. 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;

这里的第二点要求“叶子节点都是黑色的空节点”,主要是为了简化红黑树的代码实现而设置的.现在,我们暂时不管这一点.

为什么红黑树是近似平衡的

我们知道二叉查找树很多操作的性能都跟树的高度成正比。一棵极其平衡的二叉树(满二叉树或完全二叉树)的高度大约是 log2n,所以如果要证明红黑树是近似平衡的,我们只需要分析,红黑树的高度是否比较稳定地趋近 log2n 就好了。

(1)首先,我们来看,如果我们将红色节点从红黑树中去掉,那单纯包含黑色节点的红黑树的高度是多少呢?

红色节点删除之后,有些节点就没有父节点了,它们会直接拿这些节点的祖父节点(父节点的父节点)作为父节点。所以,之前的二叉树就变成了四叉树。

这时我们可以将有些节点拿出来组成一个完全二叉树,而完全二叉树的高度是 log2n ,很明显,我们的四叉树根本不会高于 log2n

(2)现在把红色节点加回去,高度会变成多少呢?

在红黑树中,红色节点不能相邻,也就是说,有一个红色节点就要至少有一个黑色节点,将它跟其他红色节点隔开.红黑树中包含最多黑色节点的路径不会超过 log2n,所以加入红色节点之后,最长路径不会超过 2log2n,也就是说,红黑树的高度近似 2log2n。

所以,红黑树的高度只比高度平衡的 AVL 树的高度(log2n)仅仅大了一倍,在性能上,下降得并不多。这样推导出来的结果不够精确,实际上红黑树的性能更好。

基本思想

不知道你有没有玩过魔方?其实魔方的复原解法是有固定算法的:遇到哪几面是什么样子,对应就怎么转几下。你只要跟着这个复原步骤,就肯定能将魔方复原。

实际上,红黑树的平衡过程跟魔方复原非常神似,大致过程就是:遇到什么样的节点排布,我们就对应怎么去调整。只要按照这些固定的调整规则来操作,就能将一个非平衡的红黑树调整成平衡的。

和AVL树一样,在进行节点的插入和删除时,就会破坏红黑树的一些规则.在红黑树中主要破坏的是以下两点:

  1. 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的;
  2. 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;

旋转

很显然,我们需要也仅仅需要处理的就是如何把被破坏了的这两点规则还原回去.在还原之前,我们需要了解两个很重要的操作:左旋与右旋(围绕某个节点的右旋),
如图,其中 a,b,r 表示子树,可以为空。

插入

红黑树规定,插入的节点必须是红色的。而且,二叉查找树中新插入的节点都是放在叶子节点上。所以,关于插入操作的平衡调整,有这样两种特殊情况,但是也都非常好处理。

  1. 如果插入节点的父节点是黑色的,那我们什么都不用做,它仍然满足红黑树的定义。
  2. 如果插入的节点是根节点,那我们直接改变它的颜色,把它变成黑色就可以了。

其他:都会违背红黑树的定义,于是我们就需要进行调整,调整的过程包含两种基础的操作:左右旋转和改变颜色。

其他情况主要有三种,如果要实现,可以对应各个情况各个击破,红黑树的平衡调整过程是一个迭代的过程。就想魔方一样!!!对应规则调整就行了

删除

删除操作的平衡调整分为两步,第一步是针对删除节点初步调整。初步调整只是保证整棵红黑树在一个节点删除之后,仍然满足最后一条定义的要求,也就是说,每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;第二步是针对关注节点进行二次调整,让它满足红黑树的第三条定义,即不存在相邻的两个红色节点。

  1. 针对删除节点初步调整

红黑树的定义中“只包含红色节点和黑色节点”,经过初步调整之后,为了保证满足红黑树定义的最后一条要求,有些节点会被标记成两种颜色,“红 - 黑”或者“黑 - 黑”。如果一个节点被标记为了“黑 - 黑”,那在计算黑色节点个数的时候,要算成两个黑色节点。

这里具体有:三种情况

  1. 针对关注节点进行二次调整
    经过初步调整之后,关注节点变成了“红 - 黑”或者“黑 - 黑”节点。针对这个关注节点,我们再分四种情况来进行二次调整。二次调整是为了让红黑树中不存在相邻的红色节点。

这里具体有:四种情况

提问:

为什么插入的节点偏偏是红色呢?

将插入的结点着色为红色,不会违背 “性质 4”。而少违背一条性质,就意味着我们需要处理的情况越少。

为什么红黑树的定义中,要求叶子节点是黑色的空节点?或者说是到底那里方便了?

只要满足这一条要求,那在任何时刻,红黑树的平衡操作都可以归结为上面的那几种情况。而且是简洁的.

给红黑树添加黑色的空的叶子节点,会不会比较浪费存储空间呢?

一张图给你,立马明白

为什么平衡的二叉树(满二叉树或完全二叉树)的高度大约是 log2n??
时间复杂度其实都跟树的高度成正比,也就是 O(height)。既然这样,现在问题就转变成另外一个了,也就是,如何求一棵包含 n 个节点的完全二叉树的高度?

树的高度就等于最大层数减一,为了方便计算,我们转换成层来表示。从图中可以看出,包含 n 个节点的完全二叉树中,第一层包含 1 个节点,第二层包含 2 个节点,第三层包含 4 个节点,依次类推,下面一层节点个数是上一层的 2 倍,第 K 层包含的节点个数就是 2^(K-1)。

不过,对于完全二叉树来说,最后一层的节点个数有点儿不遵守上面的规律了。它包含的节点个数在 1 个到 2^(L-1) 个之间(我们假设最大层数是 L)。如果我们把每一层的节点个数加起来就是总的节点个数 n。也就是说,如果节点的个数是 n,那么 n 满足这样一个关系:

n >= 1+2+4+8+...+2^(L-2)+1
n <= 1+2+4+8+...+2^(L-2)+2^(L-1)

借助等比数列的求和公式,我们可以计算出,L 的范围是 [log2(n+1), log2n +1]。完全二叉树的层数小于等于 log2n +1,也就是说,完全二叉树的高度小于等于 log2n。

应用

红黑树可以看作是二叉搜索树和AVL树的一个折中,维持平衡的同时也不需要花太多时间维护数据结构的性质。红黑树在很多地方都有应用

  • C++的STL,map和set都是用红黑树实现的。
  • 著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块。
  • epoll在内核中的实现,用红黑树管理事件块。
  • nginx用红黑树管理timer等。
  • Java的TreeMap实现。

红黑树RBTree原理(超易懂)相关推荐

  1. 左倾红黑树的原理及简单实现

    (注:以下图片全部源于<算法 第4版>) 左倾红黑树的原理及简单实现 左倾红黑树的简介 左倾红黑树的定义 左倾红黑树与2-3树的对比 左倾红黑树的颜色表示 左倾红黑树的一些基本操作 1.颜 ...

  2. 红黑树结构原理的图文讲解(非代码)

    1.引言 HashMap的基本结构是数组,链表和红黑树.以数组为基本形态,数组中的元素先以链表形式储存,当链表的长度超过8时(包含数组上的那个链表头)就会将链表转换为红黑树,以加快修改和查询效率.当然 ...

  3. 红黑树(RB-Tree)比AVL强在哪?

    前言 以前本科同学在找工作的时候,就被面试官问到过关于红黑树的问题.因为当时我的知识面不广,所以也不知道红黑树是个什么东西,也没放在心上.在看过了STL源码后才知道原来有很多底层实现都用的红黑树.简单 ...

  4. 红黑树的原理以及实现

    红黑树 红黑树基于二叉查找树的附加特性 节点是红色或黑色. 根节点是黑色. 每个叶子节点都是黑色的空节点(叶子结点指为空的叶子结点). 每个红色节点的两个子节点都是黑色的(从每个叶子到根的所有路径上不 ...

  5. C++ 泛型编程 实现红黑树RBTree

    代码如下: #include <iostream> #include <ctime> using namespace std;enum COLOR {BLACK,RED };t ...

  6. 红黑树 之 原理和算法详细介绍

    概要 目录 1 红黑树的介绍 2 红黑树的应用 3 红黑树的时间复杂度和相关证明 4 红黑树的基本操作(一) 左旋和右旋 5 红黑树的基本操作(二) 添加 6 红黑树的基本操作(三) 删除 作者:Sk ...

  7. 红黑树算法原理(从二叉搜索树讲起)

    原文:红黑树深入剖析及Java实现,本文修改了原文的一些小错误,如果想看红黑树的Java实现可以到原文去看. 红黑树是平衡二叉查找树的一种.为了深入理解红黑树,我们需要从二叉查找树开始讲起. BST ...

  8. 红黑树的原理_红黑树插入算法实现原理分析

    ­ 引言 红黑树是在实际工程中被广泛应用的一种数据结构,比如Linux中的线程调度就是使用的红黑树来管理进程控制块,而Nginx中也是使用红黑树来管理的timer,Java中的TreeMap和Tree ...

  9. linux算法设计,红黑树的原理分析和算法设计

    红黑树是60年代中期计算机科学界找寻一种算法复杂度稳定,容易实现的数据存储算法的产物.在优先级队列.字典等实用领域都有广泛地应用,更是70年代提出的关系数据库模型--B树的鼻祖.在Linux kern ...

最新文章

  1. C# GDI+ 简单绘图 (三)
  2. 你必须会的 JDK 动态代理和 CGLIB 动态代理
  3. 笔尖已加载,但未设置“查看”出口
  4. python基础语法手册format-Python format 格式化函数
  5. boost::fusion::as_vector用法的测试程序
  6. [原创] GSM/GPRS 以及CDMA区分以及相关模块选型
  7. set row count
  8. Docker Desktop 向大公司宣告收费,网友大呼:是时候弃用了!
  9. c语言十六进制字符串转整数,C语言-提取字符串中的十六进制数字并转换为一个十进制整数输出...
  10. django CBV装饰器 自定义django中间件 csrf跨站请求伪造 auth认证模块
  11. 深入理解Java main方法
  12. 关于函数式编程的思考(1)
  13. VLAN的分类与实验
  14. 机顶盒怎样配置服务器信息,网络机顶盒桌面配置服务器
  15. JavaFX的webview下载文件的一种实现思路
  16. SQLite 生成随机数字、字符串、日期、验证码以及 UUID
  17. 【MQTT学习】lesson8. :Retained 消息和 LWT
  18. MetroMusic音乐播放器开发心得
  19. 《精通.NET互操作:P/Invoke、C++ Interop和COM Interop》
  20. Java.IO.InputStream-OutputStream

热门文章

  1. 太厉害了!专属于Java程序员的学习福音,经典好文
  2. python编写游戏修改器
  3. linux 符号链接有什么用,硬链接和符号链接有什么区别?
  4. php冷饮料奶茶店在线点单系统 java小程序python
  5. 计算机网络05:传输层
  6. 实战干货:Python3小说站点爬虫|附下载
  7. till和until的区别
  8. PythonStock(36)股票系统:解决历史数据问题,使用 ak.stock_zh_a_hist 获得历史相关数据,发现AK又更新到了v1.1.1版本,更新获得历史数据代码。
  9. 如何打造高精度的写实类游戏角色
  10. 作为一名数据科学从业者,你应该知道的P值