精华内容
下载资源
问答
  • 红黑树详细图解

    2020-07-15 21:34:14
    红黑树详细图解树相关知识框架结构平衡二叉搜索树二叉搜索树平衡改进二叉搜索树AVL 树平衡因子B 树特点m 阶 B 树的性质(m ≥ 2)B 树 VS 二叉搜索树红黑树定义和性质红黑树与 B 树的等价变换红黑树的基本操作左旋右...

    blog转载链接

    树相关知识框架结构

    在这里插入图片描述

    平衡二叉搜索树

    平衡二叉搜索树(Balanced Binary Search Tree),英文简称 BBST。经典常见的平衡二叉搜索树是 AVL 树和红黑树。

    二叉搜索树

    二叉搜索树(Binary Search Tree)是二叉树的一种,英文简称 BST。又称为二叉查找树、二叉排序树。

    它的特点是任何一个结点的值都大于其左子树的所有结点的值,任何一个结点的值都小于其右子树的所有结点的值。

    平衡

    平衡(Balance):就是当结点数量固定时,左右子树的高度越接近,这棵二叉树越平衡(高度越低)。而最理想的平衡就是完全二叉树/满二叉树,高度最小的二叉树。

    在这里插入图片描述
    一棵二叉搜索树平均时间复杂度可以认为是树的高度 O(h)。像左边这棵,结点的左右子树的高度接近,属于一棵平衡二叉搜索树,O(h) = O(logn);而右边这棵,高度达到了最大,已经退化成了链表,O(h)=O(n)。

    改进二叉搜索树

    二叉树退化成链表时,性能是很低的,所以我们需要在结点的插入、删除操作之后,想办法让二叉搜索树恢复平衡(减小树的高度)。但是如果为了追求最理想的平衡,而增加了时间复杂度也不是很有必要,因此比较合理的方案就是:用尽量少的调整次数达到适度平衡

    由此引申出 AVL 树的概念。

    AVL 树

    AVL 树是最早发明的自平衡二叉搜索树之一。

    平衡因子

    平衡因子(Balance Factor):某结点的左右子树的高度差。
    每个叶子结点的平衡因子都是 0。看这棵二叉搜索树,红色数字标注了每个结点对应的平衡因子。
    在这里插入图片描述
    举例:

    8 的左子树高度为 2,右子树高度为 1,因此它的平衡因子为 1;5 的左子树高度为 0,右子树高度为 3,因此它的平衡因子为 -3;4 的左子树高度为 2,右子树高度为 4,因此它的平衡因子为 -2;

    再看这棵 AVL 树和它每个结点对应的平衡因子:
    在这里插入图片描述
    可以看到 AVL 树具有以下特点:

    • 每个结点的平衡因子只可能是 -1、0、1(如果绝对值超过 1,则认为是失衡)
    • 每个结点的左右子树高度差不超过 1
    • 搜索、插入、删除的时间复杂度是 O(logn)

    B 树

    B 树(Balanced Tree)是一种平衡的多路搜索树,多用于文件系统、数据库的实现。这是一个简单的 3 阶 B 树:
    在这里插入图片描述

    特点

    • 1 个结点可以存储超过 2 个元素,可以拥有超过 2 个子结点
    • 拥有二叉搜索树的一些性质
    • 平衡,每个结点的所有子树高度一致
    • 比较矮

    m 阶 B 树的性质(m ≥ 2)

    m 阶 B 树指的是一个结点最多拥有 m 个子结点。假设一个结点存储的元素个数为 x,那么如果这个结点是:

    • 根结点:1 ≤ x ≤ m - 1
    • 非根结点:┌ m / 2 ┐ - 1 ≤ x ≤ m - 1

    如果有子结点,子结点个数为 y = x + 1,那么如果这个结点是:

    • 根结点:2 ≤ y ≤ m
    • 非根结点:┌ m / 2 ┐ ≤ y ≤ m

    向上取整(Ceiling),指的是取比自己大的最小整数,用数学符号 ┌ ┐ 表示。
    向下取整(Floor),指的是取比自己小的最大整数,用数学符号 └ ┘ 表示。

    比如 m = 3, 子结点个数 2 ≤ y ≤ 3,这个 B 树可以称为(2,3)树、2-3 树;

    比如 m = 4, 子结点个数 2 ≤ y ≤ 4,这个 B 树可以称为(2,4)树、2-3-4 树;

    比如 m = 5, 子结点个数 3 ≤ y ≤ 4,这个 B 树可以称为(3,5)树、3-4-5 树;

    以此类推。

    B 树 VS 二叉搜索树

    在这里插入图片描述
    这是一棵二叉搜索树,通过某些父子结点合并,恰好能与上面的 B 树对应。我们可以得到结论:

    • B 树和二叉搜索树,在逻辑上是等价的
    • 多代结点合并,可以获得一个超级结点,且 n 代合并的超级结点,最多拥有2n个子结点 (至少是2n阶 B 树)

    红黑树定义和性质

    红黑树是一种含有红黑结点并能自平衡的二叉搜索树。

    为了保证平衡,红黑树必须满足以下性质:

    1. 每个结点是要么是红色或黑色
    2. 根结点必须是黑色
    3. 叶结点(外部结点、空结点)是黑色
    4. 红色结点不能连续(也就是,红色结点的孩子和父亲都是黑色)
    5. 对于每个结点,从该点至 nil(树尾端,java 中为 null 的结点)的任何路径都包含所相同个数的黑色结点

    红黑树与 B 树的等价变换

    在这里插入图片描述
    根据上面的性质,可以画出这样一棵红黑树。接下来对红黑树做等价变换,即将所有的红色结点上升一层与它的父结点放在同一行,这就很像一棵 4 阶 B 树,转换效果如下图所示。

    在这里插入图片描述
    可以得出结论:

    • 红黑树与 4 阶 B 树(2-3-4 树)具有等价性
    • 黑色结点与红色子结点融合在一起,形成 1 个 B 树结点
    • 红黑树的黑色结点个数与 4 阶 B 树的结点总个数相等

    红黑树的基本操作

    当我们对一棵平衡二叉搜索树进行插入、删除的时候,很可能会让这棵树变得失衡(最坏可能导致所有祖先结点失衡,但是父结点和非祖先结点都不可能失衡),为了达到平衡,需要对树进行旋转。而红黑树能够达到自平衡,靠的也就是左旋、右旋和变色

    旋转操作是局部的。当一侧子树的结点少了,向另一侧“借”一些结点;当一侧子树的结点多了,则“租”一些结点给另一侧。

    为了更清楚地讲解这部分内容,先声明几个概念:

    在这里插入图片描述

    • N - node:当前结点
    • P - parent:父结点
    • S - sibling:兄弟结点
    • U - uncle:叔父结点(P 的兄弟结点)
    • G - grand:祖父结点(P 的父结点)

    左旋

    左旋指的是以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。

    在这里插入图片描述
    不考虑结点颜色,可以看到左旋只影响旋转结点和其右子树的结构,把右子树的结点往左子树移动。

    右旋

    右旋指的是以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。
    在这里插入图片描述
    不考虑结点颜色,可以看到右旋只影响旋转结点和其左子树的结构,把左子树的结点往右子树移动。

    变色

    变色指的是结点的颜色由红变黑或由黑变红。

    变换规则

    将左旋、右旋和变色结合起来,得到一套变换规则

    变色:如果当前结点的父结点和叔父结点是红色,那么:

    • 把父结点和叔父结点变为黑色
    • 把祖父结点变为红色
    • 把指针定义到祖父结点

    左旋:当前结点是右子树,且父结点是红色,叔父结点是黑色,对它的父结点左旋

    右旋:当前结点是左子树,且父结点是红色,叔父结点是黑色,那么:

    • 把父结点变为黑色
    • 把祖父结点变为红色
    • 对祖父结点右旋

    红黑树搜索

    由于红黑树本来就是平衡二叉搜索树,并且搜索也不会破坏树的平衡,所以搜索算法也与平衡二叉搜索树一致:
    在这里插入图片描述
    具体步骤:

    1. 从根结点开始检索,把根结点设置为当前结点;
    2. 若当前结点为空,返回 nil。
    3. 若当前结点不为空,比较当前结点 key 与搜索 key 的大小;
    4. 若当前结点 key 等于搜索 key,那么该 key 就是搜索目标,返回当前结点。
    5. 若当前结点 key 大于搜索 key,把当前结点的左子结点设置为当前结点,重复步骤 2;
    6. 若当前结点 key 小于搜索 key,把当前结点的右子结点设置为当前结点,重复步骤 2;

    红黑树插入

    红黑树插入操作分为下面两步:

    定位插入的位置

    在这里插入图片描述
    具体步骤:

    1. 从根结点开始检索;
    2. 若根结点为空,那么插入结点设为根结点,结束。
    3. 若根结点不为空,那么把根结点设为当前结点;
    4. 若当前结点为 nil,返回当前结点的父结点,结束。
    5. 若当前结点 key 等于搜索 key,那么该 key 所在结点就是插入结点,更新结点的值,结束。
    6. 若当前结点 key 大于搜索 key,把当前结点的左子结点设置为当前结点,重复步骤 4;
    7. 若当前结点 key 小于搜索 key,把当前结点的右子结点设置为当前结点,重复步骤 4;

    插入后实现自平衡

    建议新添加的结点默认为红色,因此这样能够让红黑树的性质尽快满足。不过如果添加的结点是根结点,设为黑色即可。

    总结一下红黑树插入可能出现的所有场景。
    在这里插入图片描述
    场景 1:红黑树为空树

    红黑树的性质 2:根结点必须是黑色。

    处理:直接把插入结点设成黑色并作为根结点。

    场景 2:插入结点的 key 已存在

    二叉搜索树中不能插入相同元素,既然结点的 key 已经存在,红黑树也已平衡,无需重复插入。

    处理:

    • 将插入结点设为将要替换结点的颜色
    • 更新当前结点的值为插入结点的值

    场景 3:插入结点的父结点为黑色

    插入的结点默认是红色的,当它的父结点是黑色时,并不会破坏平衡。

    处理:直接插入。

    场景 4:插入结点的父结点为红色

    如果插入结点的父结点为红色,那么父结点不可能为根结点,所以插入结点总是存在祖父结点。这点很重要,后续的旋转操作需要祖父结点的参与。

    场景 4.1:存在叔父结点,且为红色

    由红黑树性质 4 可知:红色结点不能连续。那么此时该插入子树的红黑层数的情况是:黑-红-红。显然最简单的处理方式就是将其改为:红-黑-红。
    在这里插入图片描述
    处理:

    • 将父结点和叔父结点变为黑色
    • 将祖父结点变为红色
    • 将祖父结点设置为当前插入结点

    场景 4.2:叔父结点不存在或为黑色,插入结点的父结点是祖父结点的左子结点

    这种场景下,叔父结点所在的子树的黑色结点就比父结点所在子树的多,不满足红黑树的性质 5。

    场景 4.2.1:插入结点是左子树
    在这里插入图片描述
    处理:

    • 将父结点变为黑色
    • 将祖父结点变为红色
    • 将祖父结点右旋

    场景 4.2.2:插入结点是左子树

    这种场景显然可以转换为 4.2.1。
    在这里插入图片描述
    处理:

    • 将父结点进行左旋
    • 将父结点设为插入结点,得到场景 4.2.1
    • 进行场景 4.2.1 的处理

    场景 4.3:叔父结点不存在或为黑色,插入结点的父结点是祖父结点的右子结点

    相当于场景 4.2 的方向反转,直接看图。

    场景 4.3.1:插入结点是左子树
    在这里插入图片描述

    展开全文
  • 红黑树-图解

    2019-11-19 17:12:38
    在学习红黑树之前,咱们需要先来理解下二叉查找树(BST)。 二叉查找树 要想了解二叉查找树,我们首先看下二叉查找树有哪些特性呢? 1, 左子树上所有的节点的值均小于或等于他的根节点的值 2, 右子数上所有的...

    在学习红黑树之前,咱们需要先来理解下二叉查找树(BST)。

    二叉查找树

    要想了解二叉查找树,我们首先看下二叉查找树有哪些特性呢?

    1, 左子树上所有的节点的值均小于或等于他的根节点的值

    2, 右子数上所有的节点的值均大于或等于他的根节点的值

    3, 左右子树也一定分别为二叉排序树

    我们来看下图的这棵树,他就是典型的二叉查找树

    五分钟搞懂什么是红黑树(全程图解)

    那问题来了,为什么一定要这种结构呢?换句话说这样的结构有什么好处呢?我们就来查找下值为10的节点。它怎么一步步的找到这个节点的?步骤是怎样的?接着往下看。

    1, 查找到根节点9,看下图:

    五分钟搞懂什么是红黑树(全程图解)

    2, 由于10大于9的,所以查找到右孩子13,看下图:

    五分钟搞懂什么是红黑树(全程图解)

    3, 又因为10是小与13的,所以查找到左孩子11,看下图:

    五分钟搞懂什么是红黑树(全程图解)

    4, 这一步相比不用说了大家也都知道了,找到了左孩子,然后发现正好是10 。恰好是正要寻找的值。

    五分钟搞懂什么是红黑树(全程图解)

    可能又有童鞋会问,这不是二分查找的思想吗?确实,查找所需的最大次数等同于二叉查找树的高度。当然在插入节点的时候,也是这种思想,一层一层的找到合适的位置插入。但是二叉查找树有个比较大的缺陷,而且这个缺陷会影响到他的性能。我们先来看下有一种情况的插入操作:

    如果初始的二叉查找树只有三个节点,如下图:

    五分钟搞懂什么是红黑树(全程图解)

    我们依次插入5个节点:7,6,5,4,3,。看下图插入之后的图:

    五分钟搞懂什么是红黑树(全程图解)

    看出来了吗?有没有觉得很别扭,如果根节点足够大,那是不是“左腿”会变的特别长,也就是说查找的性能大打折扣,几乎就是线性查找了。

    那有没有好的办法解决这个问题呢?解决这种多次插入新节点而导致的不平衡?这个时候红黑树就登场了。

    红黑树

    红黑树就是一种平衡的二叉查找树,说他平衡的意思是他不会变成“瘸子”,左腿特别长或者右腿特别长。除了符合二叉查找树的特性之外,还具体下列的特性:

    1. 节点是红色或者黑色

    2. 根节点是黑色

    3. 每个叶子的节点都是黑色的空节点(NULL)

    4. 每个红色节点的两个子节点都是黑色的。

    5. 从任意节点到其每个叶子的所有路径都包含相同的黑色节点。

    看下图就是一个典型的红黑树:五分钟搞懂什么是红黑树(全程图解)

    很多童鞋又会惊讶了,天啊这个条条框框也太多了吧。没错,正式因为这些规则,才能保证红黑树的自平衡。最长路径不超过最短路径的2倍。

    当插入和删除节点,就会对平衡造成破坏,这时候需要对树进行调整,从而重新达到平衡。那什么情况下会破坏红黑树的规则呢?

    1,我们看下图:

    五分钟搞懂什么是红黑树(全程图解)

    向原来的红黑树插入值为14的新节点,由于父节点15是黑色节点,所以这种情况没有破坏结构,不需要做任何的改变。

    2,向原树插入21呢?,看下图:

    五分钟搞懂什么是红黑树(全程图解)

    由于父节点22是红色节点,因此这种情况打破了红黑树的规则4,必须作出调整。那么究竟该怎么调整呢?有两种方式【变色】【旋转】分为【左旋转】和【右旋转】。

    【变色】:

    为了符合红黑树的规则,会把节点红变黑或者黑变红。下图展示的是红黑树的部分,需要注意节点25并非根节点。因为21和22链接出现红色,不符合规则4,所以把22红变黑:

    五分钟搞懂什么是红黑树(全程图解)

    但这样还是不符合规则5,所以需要把25黑变红,看下图:

    五分钟搞懂什么是红黑树(全程图解)

    你以为现在结束了?天真,因为25和27又是两个连续的红色节点(规则4),所以需要将27红变黑。

    五分钟搞懂什么是红黑树(全程图解)

    终于结束了,都满足规则了,舒服多了。

    【左旋转】

    也就是逆时针旋转两个节点,使父节点被自己的右孩子取代,而自己成为自己的左孩子,听起来吓死人,直接看图吧:

    五分钟搞懂什么是红黑树(全程图解)

    【右旋转】

    顺时针旋转两个节点,使得自己的父节点被左孩子取代,而自己成为自己的右孩子,看不懂直接看图吧:

    五分钟搞懂什么是红黑树(全程图解)

    看起来这么复杂,到底怎么用呢?确实很复杂,我们讲下典型的例子,大家参考下:

    以刚才插入21节点的例子:

    五分钟搞懂什么是红黑树(全程图解)

    首先我们需要做的是变色,把节点25以及下方的节点变色:

    五分钟搞懂什么是红黑树(全程图解)

    由于17和25是连续的两个红色节点,那么吧节点17变黑吗?这样是不行的,你想这样一来不就打破了规则4了吗,而且根据规则2,也不可能吧13变成红色。变色已经无法解决问题了,所以只能进行旋转了。13当成X,17当成Y,左旋转试试看:

    五分钟搞懂什么是红黑树(全程图解)

    五分钟搞懂什么是红黑树(全程图解)五分钟搞懂什么是红黑树(全程图解)

    由于根节点必须是黑色,所以需要变色,结果如下图:

    五分钟搞懂什么是红黑树(全程图解)

    继续,其中有两条路径(17-)8->6->NULL)的黑色节点个数不是3,是4不符合规则。

    这个时候需要把13当做X,8当做Y,进行右旋转:

    五分钟搞懂什么是红黑树(全程图解)五分钟搞懂什么是红黑树(全程图解)五分钟搞懂什么是红黑树(全程图解)

    最后根据规则变色:

    五分钟搞懂什么是红黑树(全程图解)

    这样一来,我们终于结束了,经过调整之后符合规则。

    那我们费这么大力气,这么复杂,这东西用在哪里,有哪些应用呢?

    其实STL中的map就是用的红黑树。

    总结:

    红黑色的大体思想就是上面描述的那样,里面还有很多情况要考虑,本文只是简单的讲述思想,大家有兴趣可以去百度上看各种情况的考虑。谢谢大家的支持!

    展开全文
  • 红黑树简明图解

    2014-08-18 14:19:39
    一、红黑树 1、红黑树为一颗erhc

    一、概念

    1、红黑树。红黑树为二叉排序树,节点分红黑两色,根节点为黑色,并满足如下两个性质:

    2、颜色性。沿任意路径上红色节点不能连续出现。

    3、平衡性。对于任意节点x,从x出发至任一叶节点的路径上黑色节点数目相同。

    4、哑元素。红黑树节点有三个指针:left、right、parent,当没有对应节点不存在时指针不为null,而是指向一个名叫NIL的哑元素。这使任意节点都有叶节点,在本文的分析中做次默认,但不会显示标注出NIL来。NIL为分析问题提供了巨大便利。

    5、黑高度。从x节点至任意叶节点的路径上黑色节点的数目(不包括x)为x的黑高度,但包括x也无所谓。

    二、插入

    红黑树与AVL树一样把新节点x插入为一个叶节点,并将其涂为红色。

    删除任意红色节点不会引起任何平衡性和颜色性问题;

    插入一个红色叶节点最多x会与其父亲节点红色冲突,但不会引起平衡性问题;

    插入或删除一个黑色节点都会引起平衡性失调。

    平衡性失调比红色冲突繁琐的多,因此选择红色。红黑树的插入就是解决红色冲突问题,红黑树的删除就是解决平衡性失调问题。

    既然插入一个红叶节点只会与父亲的红色冲突,怎么解决呢?不妨设插入节点为x,x的叔几点为uncle,解决方法如下图:


    这只是父亲节点为祖父节点左孩子的情况,父亲为右孩子的情况同理。这个问题的本质是当前节点与父亲的红色冲突,所以把它叫做红父亲冲突问题。

    三、删除

    删除操作与AVL树一样,都是找到一个无孩子或只有一个孩子的后继节点y代为删除,y的孩子x取代了y的位置,如果y是红色不会引起两个性质的问题,如果y为黑色会引起原来通过y的路径(即现在通过x的路径)黑高度少了1,y的父节点(现为x的父节点)平衡性出了问题。设父节点为p,兄弟节点为bro,解决方法如下图:


    上图只是解决x为左孩子的问题,x为有孩子的情况同理。这个问题的本质就是x子树的高度少了1,所以把它叫做高度缺失问题。

    上图中黑色红色都是黑红节点,白节点是无法知其颜色的节点,在最后一栏还有两个蓝节点,也是颜色未知的节点,与白色不同的是这里表达了“bro变为p的颜色”这个意思,与其他的颜色转换并无不同。本文中节点的着色都是严格的,每个节点的着色都可以简单推理出来,就不写了。

    可以看到在调整时分那么多情况更多是为了达到“bro右孩子为红色”那一栏的效果,因为在那一栏中问题得到了最直接的解决。

    四、分析

    在眼花缭乱的操作中可能不容易看清到底怎么回事,假设节点x的黑高度(包含x自身)为height(x),这里用一个例子简单说明:


    操作:改变ac颜色并左旋a。子树123456的根节点不妨就用123456来表示。

    子树bde本身没有改变,所以其内部没有发生颜色冲突或失去平衡的问题,节点abcde也都没有颜色冲突的问题。

    操作前,height(c)=height(d)=height(b),height(1)=height(6),整个子树的黑高度为height(6)+2。

    操作后,bde平衡,height(d)=height(b)未变所以a节点仍平衡,height(a)=height(1)+1=height(6)+1=height(e),所以c节点仍平衡,整棵子树黑高度为height(6)+2未变所以祖先节点也没有发生平衡性的问题。

    所以这次操作是合法的。

    展开全文
  • 30分钟搞懂红黑树图解

    千次阅读 2019-11-07 17:33:00
    作者:coolblogsegmentfault.com/a/1190000012728513红黑树简介红黑树是一种自平衡的二叉查找树,是一种高效的查找树。它是由 Rudolf Bayer 于1972年发明,在当时被称为对称二叉 B 树(symmetric binary B-trees)。...

    点击上方“后端技术精选”,选择“置顶公众号”

    技术文章第一时间送达!

    作者:coolblog

    segmentfault.com/a/1190000012728513


    红黑树简介

    红黑树是一种自平衡的二叉查找树,是一种高效的查找树。它是由 Rudolf Bayer 于1972年发明,在当时被称为对称二叉 B 树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的红黑树

    红黑树具有良好的效率,它可在 O(logN) 时间内完成查找、增加、删除等操作。因此,红黑树在业界应用很广泛,比如 Java 中的 TreeMap,JDK 1.8 中的 HashMap、C++ STL 中的 map 均是基于红黑树结构实现的。

    考虑到红黑树是一种被广泛应用的数据结构,所以我们很有必要去弄懂它。

    640?wx_fmt=jpeg

    红黑树的性质

    学过二叉查找树的同学都知道,普通的二叉查找树在极端情况下可退化成链表,此时的增删查效率都会比较低下。为了避免这种情况,就出现了一些自平衡的查找树,比如 AVL,红黑树等。这些自平衡的查找树通过定义一些性质,将任意节点的左右子树高度差控制在规定范围内,以达到平衡状态。以红黑树为例,红黑树通过如下的性质定义实现自平衡:

    1. 节点是红色或黑色。

    2. 根是黑色。

    3. 所有叶子都是黑色(叶子是NIL节点)。

    4. 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)

    5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点(简称黑高)。

    有了上面的几个性质作为限制,即可避免二叉查找树退化成单链表的情况。但是,仅仅避免这种情况还不够,这里还要考虑某个节点到其每个叶子节点路径长度的问题。如果某些路径长度过长,那么,在对这些路径上的及诶单进行增删查操作时,效率也会大大降低。这个时候性质4和性质5用途就凸显了,有了这两个性质作为约束,即可保证任意节点到其每个叶子节点路径最长不会超过最短路径的2倍。原因如下:

    当某条路径最短时,这条路径必然都是由黑色节点构成。当某条路径长度最长时,这条路径必然是由红色和黑色节点相间构成(性质4限定了不能出现两个连续的红色节点)。而性质5又限定了从任一节点到其每个叶子节点的所有路径必须包含相同数量的黑色节点。

    此时,在路径最长的情况下,路径上红色节点数量 = 黑色节点数量。该路径长度为两倍黑色节点数量,也就是最短路径长度的2倍。举例说明一下,请看下图:

    640?wx_fmt=jpeg

    上图画出了从根节点 M 出发的到其叶子节点的最长和最短路径。这里偷懒只画出了两条最长路径,实际上最长路径有4条,分别为:

    M -> Q -> O -> N

    M -> Q -> O -> p

    M -> Q -> Y -> X

    M -> Q -> Y -> Z

    长度为4,最短路径为 M -> E,长度为2。最长路径的长度正好为最短路径长度的2倍。

    前面说了关于红黑树的一些性质,这里还需要补充一些其他方面的东西。在红黑树简介一节中说到红黑树被发明出来的时候并不叫红黑树,而是叫做对称二叉 B 树,从名字中可发现红黑树和 B 树(这里指的是2-3树)或许有一定的关联,事实也正是如此。

    如果对红黑树的性质稍加修改,就能让红黑树和B树形成一一对应的关系。关于红黑树和 B 树关系的细节这里不展开说明了,有兴趣的同学可以参考《算法》第4版,那本书上讲的很透彻。

    红黑树操作

    红黑树的基本操作和其他树形结构一样,一般都包括查找、插入、删除等操作。前面说到,红黑树是一种自平衡的二叉查找树,既然是二叉查找树的一种,那么查找过程和二叉查找树一样,比较简单,这里不再赘述。

    相对于查找操作,红黑树的插入和删除操作就要复杂的多。尤其是删除操作,要处理的情况比较多,不过大家如果静下心来去看,会发现其实也没想的那么难。好了,废话就说到这,接下来步入正题吧。

    旋转操作

    在分析插入和删除操作前,这里需要插个队,先说明一下旋转操作,这个操作在后续操作中都会用得到。旋转操作分为左旋和右旋,左旋是将某个节点旋转为其右孩子的左孩子,而右旋是节点旋转为其左孩子的右孩子。这话听起来有点绕,所以还是请看下图:

    640?wx_fmt=jpeg

    上图包含了左旋和右旋的示意图,这里以右旋为例进行说明,右旋节点 M 的步骤如下:

    1. 将节点 M 的左孩子引用指向节点 E 的右孩子

    2. 将节点 E 的右孩子引用指向节点 M,完成旋转

    640?wx_fmt=jpeg

    上面分析了右旋操作,左旋操作与此类似,大家有兴趣自己画图试试吧,这里不再赘述了。旋转操作本身并不复杂,这里先分析到这吧。

    插入

    红黑树的插入过程和二叉查找树插入过程基本类似,不同的地方在于,红黑树插入新节点后,需要进行调整,以满足红黑树的性质。性质1规定红黑树节点的颜色要么是红色要么是黑色,那么在插入新节点时,这个节点应该是红色还是黑色呢?

    答案是红色,原因也不难理解。如果插入的节点是黑色,那么这个节点所在路径比其他路径多出一个黑色节点,这个调整起来会比较麻烦(参考红黑树的删除操作,就知道为啥多一个或少一个黑色节点时,调整起来这么麻烦了)。

    如果插入的节点是红色,此时所有路径上的黑色节点数量不变,仅可能会出现两个连续的红色节点的情况。这种情况下,通过变色和旋转进行调整即可,比之前的简单多了。

    接下来,将分析插入红色节点后红黑树的情况。这里假设要插入的节点为 N,N 的父节点为 P,祖父节点为 G,叔叔节点为 U。插入红色节点后,会出现5种情况,分别如下:

    情况一:

    插入的新节点 N 是红黑树的根节点,这种情况下,我们把节点 N 的颜色由红色变为黑色,性质2(根是黑色)被满足。同时 N 被染成黑色后,红黑树所有路径上的黑色节点数量增加一个,性质5(从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点)仍然被满足。

    640?wx_fmt=jpeg

    情况二:

    N 的父节点是黑色,这种情况下,性质4(每个红色节点必须有两个黑色的子节点)和性质5没有受到影响,不需要调整。

    640?wx_fmt=jpeg

    情况三:

    N 的父节点是红色(节点 P 为红色,其父节点必然为黑色),叔叔节点 U 也是红色。由于 P 和 N 均为红色,所有性质4被打破,此时需要进行调整。这种情况下,先将 P 和 U 的颜色染成黑色,再将 G 的颜色染成红色。此时经过 G 的路径上的黑色节点数量不变,性质5仍然满足。但需要注意的是 G 被染成红色后,可能会和它的父节点形成连续的红色节点,此时需要递归向上调整。

    640?wx_fmt=jpeg

    情况四:

    N 的父节点为红色,叔叔节点为黑色。节点 N 是 P 的右孩子,且节点 P 是 G 的左孩子。此时先对节点 P 进行左旋,调整 N 与 P 的位置。接下来按照情况五进行处理,以恢复性质4。

    640?wx_fmt=jpeg

    这里需要特别说明一下,上图中的节点 N 并非是新插入的节点。当 P 为红色时,P 有两个孩子节点,且孩子节点均为黑色,这样从 G 出发到各叶子节点路径上的黑色节点数量才能保持一致。既然 P 已经有两个孩子了,所以 N 不是新插入的节点。情况四是由以 N 为根节点的子树中插入了新节点,经过调整后,导致 N 被变为红色,进而导致了情况四的出现。考虑下面这种情况(PR 节点就是上图的 N 节点):640?wx_fmt=jpeg

    如上图,插入节点 N 并按情况三处理。此时 PR 被染成了红色,与 P 节点形成了连续的红色节点,这个时候就需按情况四再次进行调整。

    情况五:

    N 的父节点为红色,叔叔节点为黑色。N 是 P 的左孩子,且节点 P 是 G 的左孩子。此时对 G 进行右旋,调整 P 和 G 的位置,并互换颜色。经过这样的调整后,性质4被恢复,同时也未破坏性质5。

    640?wx_fmt=jpeg

    插入总结

    上面五种情况中,情况一和情况二比较简单,情况三、四、五稍复杂。但如果细心观察,会发现这三种情况的区别在于叔叔节点的颜色,如果叔叔节点为红色,直接变色即可。如果叔叔节点为黑色,则需要选选择,再交换颜色。当把这三种情况的图画在一起就区别就比较容易观察了,如下图:

    640?wx_fmt=jpeg

    删除

    相较于插入操作,红黑树的删除操作则要更为复杂一些。删除操作首先要确定待删除节点有几个孩子,如果有两个孩子,不能直接删除该节点。而是要先找到该节点的前驱(该节点左子树中最大的节点)或者后继(该节点右子树中最小的节点),然后将前驱或者后继的值复制到要删除的节点中,最后再将前驱或后继删除。

    由于前驱和后继至多只有一个孩子节点,这样我们就把原来要删除的节点有两个孩子的问题转化为只有一个孩子节点的问题,问题被简化了一些。我们并不关心最终被删除的节点是否是我们开始想要删除的那个节点,只要节点里的值最终被删除就行了,至于树结构如何变化,这个并不重要。

    红黑树删除操作的复杂度在于删除节点的颜色,当删除的节点是红色时,直接拿其孩子节点补空位即可。因为删除红色节点,性质5(从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点)仍能够被满足。当删除的节点是黑色时,那么所有经过该节点的路径上的黑节点数量少了一个,破坏了性质5。如果该节点的孩子为红色,直接拿孩子节点替换被删除的节点,并将孩子节点染成黑色,即可恢复性质5。但如果孩子节点为黑色,处理起来就要复杂的多。分为6种情况,下面会展开说明。

    在展开说明之前,我们先做一些假设,方便说明。这里假设最终被删除的节点为X(至多只有一个孩子节点),其孩子节点为NX的兄弟节点为SS的左节点为 SL,右节点为 SR。接下来讨论是建立在节点 X 被删除,节点 N 替换X的基础上进行的。这里说明把被删除的节点X特地拎出来说一下的原因是防止大家误以为节点N会被删除,不然后面就会看不明白。

    640?wx_fmt=jpeg

    在上面的基础上,接下来就可以展开讨论了。红黑树删除有6种情况,分别是:

    情况一:

    N 是新的根。在这种情形下,我们就做完了。我们从所有路径去除了一个黑色节点,而新根是黑色的,所以性质都保持着。

    上面是维基百科中关于红黑树删除的情况一说明,由于没有配图,看的有点晕。经过思考,我觉得可能会是下面这种情形:

    要删除的节点 X 是根节点,且左右孩子节点均为空节点,此时将节点 X 用空节点替换完成删除操作。

    可能还有其他情形,大家如果知道,烦请告知。

    情况二:

    S 为红色,其他节点为黑色。这种情况下可以对 N 的父节点进行左旋操作,然后互换 P 与 S 颜色。但这并未结束,经过节点 P 和 N 的路径删除前有3个黑色节点(P -> X -> N),现在只剩两个了(P -> N)。比未经过 N 的路径少一个黑色节点,性质5仍不满足,还需要继续调整。不过此时可以按照情况四、五、六进行调整。

    640?wx_fmt=jpeg

    情况三:

    N 的父节点,兄弟节点 S 和 S 的孩子节点均为黑色。这种情况下可以简单的把 S 染成红色,所有经过 S 的路径比之前少了一个黑色节点,这样经过 N 的路径和经过 S 的路径黑色节点数量一致了。但经过 P 的路径比不经过 P 的路径少一个黑色节点,此时需要从情况一开始对 P 进行平衡处理。

    640?wx_fmt=jpeg

    情况四:

    N 的父节点是红色,S 和 S 孩子为黑色。这种情况比较简单,我们只需交换 P 和 S 颜色即可。这样所有通过 N 的路径上增加了一个黑色节点,所有通过 S 的节点的路径必然也通过 P 节点,由于 P 与 S 只是互换颜色,并不影响这些路径。

    640?wx_fmt=jpeg

    这里需要特别说明一下,上图中的节点 N 并非是新插入的节点。当 P 为红色时,P 有两个孩子节点,且孩子节点均为黑色,这样从 G 出发到各叶子节点路径上的黑色节点数量才能保持一致。既然 P 已经有两个孩子了,所以 N 不是新插入的节点。情况四是由以 N 为根节点的子树中插入了新节点,经过调整后,导致 N 被变为红色,进而导致了情况四的出现。考虑下面这种情况(PR 节点就是上图的 N 节点):

    640?wx_fmt=jpeg

    情况五:

    S 为黑色,S 的左孩子为红色,右孩子为黑色。N 的父节点颜色可红可黑,且 N 是 P 左孩子。这种情况下对 S 进行右旋操作,并互换 S 和 SL 的颜色。此时,所有路径上的黑色数量仍然相等,N 兄弟节点的由 S 变为了 SL,而 SL 的右孩子变为红色。接下来我们到情况六继续分析。

    640?wx_fmt=jpeg

    情况六:

    S 为黑色,S 的右孩子为红色。N 的父节点颜色可红可黑,且 N 是其父节点左孩子。这种情况下,我们对 P 进行左旋操作,并互换 P 和 S 的颜色,并将 SR 变为黑色。因为 P 变为黑色,所以经过 N 的路径多了一个黑色节点,经过 N 的路径上的黑色节点与删除前的数量一致。对于不经过 N 的路径,则有以下两种情况:

    1. 该路径经过 N 新的兄弟节点 SL ,那它之前必然经过 S 和 P。而 S 和 P 现在只是交换颜色,对于经过 SL 的路径不影响。

    2. 该路径经过 N 新的叔叔节点 SR,那它之前必然经过 P、 S 和 SR,而现在它只经过 S 和 SR。在对 P 进行左旋,并与 S 换色后,经过 SR 的路径少了一个黑色节点,性质5被打破。另外,由于 S 的颜色可红可黑,如果 S 是红色的话,会与 SR 形成连续的红色节点,打破性质4(每个红色节点必须有两个黑色的子节点)。此时仅需将 SR 由红色变为黑色即可同时恢复性质4和性质5(从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。)。

    640?wx_fmt=jpeg

    删除总结

    红黑树删除的情况比较多,大家刚开始看的时候可能会比较晕。可能会产生这样的疑问,为啥红黑树会有这种删除情况,为啥又会有另一种情况,它们之间有什么联系和区别?

    和大家一样,我刚开始看的时候也有这样的困惑,直到我把所有情况对应的图形画在一起时,拨云见日,一切都明了了。此时天空中出现了4个字,原来如此、原来如此、原来如此。所以,请看图吧:

    640?wx_fmt=jpeg

    总结

    红黑树是一种重要的二叉树,应用广泛,但在很多数据结构相关的书本中出现的次数并不多。很多书中要么不说,要么就一笔带过,并不会进行详细的分析,这可能是因为红黑树比较复杂的缘故。

    我在学习红黑树的时候也找了很多资料,但总体感觉讲的都不太好。尤其是在我学习删除操作的时候,很多资料是实在人看不下去,看的我很痛苦。直到我看到维基百科上关于红黑树的分析时,很是欣喜。

    这篇文章分析的很有条理,言简意赅,比很多资料好了太多。本文对红黑树的分析也主要参考了维基百科中的红黑树分析,并对维基百科中容易让人产生疑问和误解的地方进行了说明。同时维基百科中文版红黑树文中的图片较为模糊,这里我重新进行了绘制。

    需要说明的是,维基百科中文版无法打开了,文中关于维基百科的链接都是英文版的。另外在给大家推荐一个数据结构可视化的网站,里面包含常见数据结构可视化过程,地址为:

    https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

    另外,由于红黑树本身比较复杂,实现也较为复杂。在写这篇文章之前,我曾尝试过用 Java 语言实现红黑树的增删操作,最终只写出了新增节点操作,删除没做出来。而且自己写的新增逻辑实在在太繁琐,写的不好看,没法拿出来 show。

    所以最后把 Java 中的 TreeMap 增删相关源码拷出来,按照自己的需求把源码修改了一下,也勉强算是实现了红黑树吧。代码放到了 github 上,传送门 ->

    https://github.com/code4wt/basic_algorithm/blob/master/src/main/java/search/RBTree.java

    最后,如果你也在学习红黑树,希望这篇文章能够帮助到你。另外,由于红黑树本身比较复杂,加之本人水平有限,难免会出一些错误。如果有错,还望大家指出来,我们共同讨论。

    参考

    https://book.douban.com/subject/19952400/

    https://en.wikipedia.org/wiki/Red%E2%80%93black_tree

    END

    Java面试题专栏

    展开全文
  • 红黑树(RBTree)之删除结点图解

    千次阅读 2013-11-06 20:59:29
    红黑树删除结点图解
  • 相对于红黑树插入操作,删除操作复杂的多。 第一:先看最简单情况,即删除红色节点。删除红色节点,不影响红黑树平衡性质,如图:   只需要删除红色节点,不需要进行调整,因为不影响红黑树的性质。 ...
  • 红黑树(Red Black Tree)是一种自平衡的二叉搜索树(Self-balancing Binary Search Tree)。以前也叫做平衡二叉 B 树(Symmetric Binary B-tree)。 预备知识 树的知识框架结构如下图所示: 平衡二叉搜索树 平衡...
  • 图解红黑树

    2019-02-02 09:35:45
    图解红黑树预先了解的知识什么是红黑树红黑树解决的问题红黑树的定义 预先了解的知识 二叉树 什么是红黑树 红黑树解决的问题  &amp...
  • 1、二叉查找 二叉查找BST(binary search/sort tree)又叫二叉搜索或者二叉排序,它首先是一个二叉树,而且必须满足下面的条件: 1)若左子树不空,则左子树上所有结点的值均小于它的根节点的值(左小) ...
  • 红黑树图解

    2019-10-01 15:23:58
    二叉查找 要想了解二叉查找,我们首先看下二叉查找有哪些特性呢? 1, 左子树上所有的节点的值均小于或等于他的根节点的值 2, 右子数上所有的节点的值均大于或等于他的根节点的值 3, 左右子树也一定分别...
  • javascript图解红黑树

    2021-02-28 22:43:54
    案例插入10插入9插入8插入7插入6插入5插入4插入3插入2**插入1**四、红黑树删除操作 一、红黑树的五条规则 红黑树除了符合二叉搜索树的基本规则外,还添加了以下特性: 规则1:节点是红色或黑色的; 规则2:根节点...
  • 图解红黑树之插入与删除

    千次阅读 2016-05-08 02:41:47
    旋转操作以后,不会改变红黑树的平衡性,是一种“安全操作”。 左旋转 左边的树为2-3搜索树,右边的两棵树为左旋转的动作示意图从图中可以看出来,旋转动作前后,红黑树对应的2-3搜索树并没有发生改变。右旋转右...
  • 前言 红黑树,对很多童鞋来说,是既熟悉又陌生。熟悉是因为在校学习期间,准备...那么我将带领大家重新认识下红黑树,用简单的语言,搞懂红黑树。 在学习红黑树之前,咱们需要先来理解下二叉查找树(BST)。 二...
  • 想要了解更多不掺水的原创,请戳上方蓝色字体:政采云前端团队 关注我们吧~本文首发于政采云前端团队博客:通俗易懂的红黑树图解(上)https://www.zoo.team/article/red-black-tree-1前言○ 学习红黑树难吗?红黑树...
  • 红黑树的5个性质: 性质1. 节点是红色或黑色。 性质2. 根节点是黑色。 性质3.所有叶子都是黑色。(叶子是NUIL节点) 性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的...
  • 红黑树-性质图解

    2018-06-18 18:04:18
    RBT 红黑树AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多;红黑是弱平衡的,用非严格的平衡来换取增删节点时候旋转次数的降低;所以简单说,搜索的次数远远大于插入和删除...
  • 人生有涯,学海无涯 前言: 为了解决二叉树多次插入新的节点导致不平衡的问题,红黑树应运而生了。 红黑树的特性: 结点是红色或黑色。...下图中这棵树,就是一颗典型的...当插入或删除节点的时候,红黑树的规则有.
  • 了解红黑树之前,最好先了解一下二叉搜索树以及平衡二叉树。毕竟红黑树属于平衡二叉树的一个变种。 【二叉搜索树】(Binary Search Tree); 【平衡二叉树】(AVL Tree); 1. 二叉搜索树 这里简单介绍一下二叉...
  • 红黑树(全程图解

    2021-08-18 23:57:54
    那么我将带领大家重新认识下红黑树,用简单的语言,搞懂红黑树。 在学习红黑树之前,咱们需要先来理解下二叉查找树(BST)。 二叉查找树 要想了解二叉查找树,我们首先看下二叉查找树有哪些特性呢? 1, 左子树...
  • 红黑树

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,279
精华内容 911
关键字:

红黑树删除图解