来自公众号: 51CTO技术栈 链接: https://www.cnblogs.com/LiaHon/p/11203229.html
学过数据结构都知道二叉树的概念,而又有多种比较常见的二叉树类型,比如完全二叉树、满二叉树、二叉搜索树、均衡二叉树、完美二叉树等。
今天我们要说的红黑树就是就是一棵非严格均衡的二叉树,均衡二叉树又是在二叉搜索树的基础上增加了自动维持平衡的性质,插入、搜索、删除的效率都比较高。红黑树也是实现 TreeMap 存储结构的基石。
二叉搜索树又叫二叉查找树、二叉排序树,我们先看一下典型的二叉搜索树,这样的二叉树有何规则特点呢?
二叉搜索树有如下几个特点:
节点的左子树小于节点本身
节点的右子树大于节点本身
左右子树同样为二叉搜索树
二叉搜索树是均衡二叉树的基础,我们看一下它的搜索步骤如何。我们要从二叉树中找到值为 58 的节点。
第二步:比较我们要找的值 58 与该节点的大小。
如果等于,那么恭喜,已经找到;如果小于,继续找左子树;如果大于,那么找右子树。
第三步:按照第二步的规则继续找。
看到这样的二叉搜索树是否很别扭,典型的大长腿瘸子,但它也是二叉搜索树,如果我们要找值为 50 的节点,基本上和单链表查询没多大区别了,性能将大打折扣。
这个时候我们的均衡二叉树就粉墨登场了,均衡二叉树就是在二叉搜索树的基础上添加了自动维持平衡的性质。
经过了自动平衡,再去找值为 50 的节点,查找性能将提升很多。红黑树就是非严格均衡的二叉搜索树。
红黑树具体有哪些规则特点呢?具体如下:
节点分为红色或者黑色。
根节点必为黑色。
叶子节点都为黑色,且为 null。
连接红色节点的两个子节点都为黑色(红黑树不会出现相邻的红色节点)。
从任意节点出发,到其每个叶子节点的路径中包含相同数量的黑色节点。
新加入到红黑树的节点为红色节点。
规则看着好像挺多,没错,因为红黑树也是均衡二叉树,需要具备自动维持平衡的性质,上面的 6 条就是红黑树给出的自动维持平衡所需要具备的规则。
首先解读一下规则,除了字面上看到的意思,还隐藏了哪些意思呢?
①从根节点到叶子节点的最长路径不大于最短路径的 2 倍
怎么样的路径算最短路径?从规则 5 中,我们知道从根节点到每个叶子节点的黑色节点数量是一样的,那么纯由黑色节点组成的路径就是最短路径。
什么样的路径算是最长路径?根据规则 4 和规则 3,若有红色节点,则必然有一个连接的黑色节点,当红色节点和黑色节点数量相同时,就是最长路径,也就是黑色节点(或红色节点)*2。
②为什么说新加入到红黑树中的节点为红色节点
从规则 4 中知道,当前红黑树中从根节点到每个叶子节点的黑色节点数量是一样的,此时假如新的是黑色节点的话,必然破坏规则。
但加入红色节点却不一定,除非其父节点就是红色节点,因此加入红色节点,破坏规则的可能性小一些,下面我们也会举例来说明。
什么情况下,红黑树的结构会被破坏呢?破坏后又怎么维持平衡,维持平衡主要通过两种方式【变色】和【旋转】,【旋转】又分【左旋】和【右旋】,两种方式可相互结合。
下面我们从插入和删除两种场景来举例说明。
很明显,这个时候结构依然遵循着上述 6 大规则,无需启动自动平衡机制调整节点平衡状态。
很明显现在的结构不遵循规则 4 了,这个时候就需要启动自动平衡机制调整节点平衡状态。
变色
我们可以通过变色的方式,使结构满足红黑树的规则:
首先解决结构不遵循规则 4 这一点(红色节点相连,节点 49-51),需将节点 49 改为黑色。
此时我们发现又违反了规则 5(56-49-51-XX 路径中黑色节点超过了其他路径),那么我们将节点 45 改为红色节点。
哈哈,妹的,又违反了规则 4(红色节点相连,节点 56-45-43),那么我们将节点 56 和节点 43 改为黑色节点。
但是我们发现此时又违反了规则 5(60-56-XX 路径的黑色节点比 60-68-XX 的黑色节点多),因此我们需要调整节点 68 为黑色。
完成!
最终调整完成后的树为:
如在下面这棵树的基础上,加入节点 65:
插入节点 65 后进行以下步骤:
左旋操作步骤如下:首先断开节点 PL 与右子节点 G 的关系,同时将其右子节点的引用指向节点 C2;然后断开节点 G 与左子节点 C2 的关系,同时将 G 的左子节点的应用指向节点 PL。
右旋操作步骤如下:首先断开节点 G 与左子节点 PL 的关系,同时将其左子节点的引用指向节点 C2;然后断开节点 PL 与右子节点 C2 的关系,同时将 PL 的右子节点的应用指向节点 G。
左左节点旋转
规则如下:以祖父节点【右旋】,搭配【变色】。
按照规则,步骤如下:
左右节点旋转
按照规则,步骤如下:
右左节点旋转
规则如下:先父节点【右旋】,然后祖父节点【左旋】,搭配【变色】。
按照规则,步骤如下:
右右节点旋转
按照规则,步骤如下:
红黑树插入总结
若都为 null,则将当前节点设置为 null,当然如果违反规则了,则按需调整,如【变色】以及【旋转】。
子节点都是非 null 节点
红黑树删除总结
删除的是根节点,则直接将根节点置为 null。
待删除节点的左右子节点都为 null,删除时将该节点置为 null。
待删除节点的左右子节点有一个有值,则用有值的节点替换该节点即可。
待删除节点的左右子节点都不为 null,则找前驱或者后继,将前驱或者后继的值复制到该节点中,然后删除前驱或者后继。
节点删除后可能会造成红黑树的不平衡,这时我们需通过【变色】+【旋转】的方式来调整,使之平衡,上面也给出了例子,建议大家多多练习,而不必背下来。
作者:梁洪
简介:网名工匠初心,热爱技术,喜欢钻研与分享,6 年 Java 开发经验,专注于 Java 以及 Spring 生态圈,同时也喜欢研究物联网、大数据、AI 等前沿技术,带过 15 人以下的小团队,做过项目管理,现在是一家软件公司的部门经理。
●编号1054,输入编号直达本文
●输入m获取文章目录
程序员数学学习
锻炼数学逻辑思维