红黑树详解一

说在前面

《算法导论》中的红黑树

  1. 每个节点或者是红色的,或者是黑色的
  2. 根节点是黑色的
  3. 每一个叶子节点(最后的空节点)是黑色的
  4. 如果一个节点是红色的,那么它的孩子节点是黑色的
  5. 从任意一个节点到叶子节点,经过的黑色节点个数是一样的。

对于很多初学者来说,扔出这些红黑树的定义,或许也很难理解红黑树,为什么红黑树要把节点定义成红色或者是黑色。

首先我想提出另一种树结构,2-3树,如果理解了 2-3 树与红黑树之间的关系,或许会发现红黑树并不难!


一、2-3 树

学习 2-3 树,不仅对于理解红黑树有帮助,对于理解 B 类树,也是有巨大帮助的!

2-3 树与以往我们学习的树结构有所不同,不管我们之前学习的二叉树,二叉搜索树,AVL 树,它们每个节点的结构都是相同的,而 2-3 树有所不同。

首先,它满足二分搜索树的基本性质,但是在满足这个基本性质的基础上,它却并不是一种二叉树。它的节点可以存放一个元素或者两个元素,如下图所示:
在这里插入图片描述
存放一个元素的节点它可以拥有2个孩子,我们可以叫做 2 节点,存放2个元素的节点可以拥有3个孩子,我们可以叫做 3 节点。这也是 2-3 树名字的由来。
在这里插入图片描述
比如,一颗 2-3 树如下图所示:
在这里插入图片描述
你也可以简单验证一下他所满足的二分搜索树的基本性质。对于 2-3 树来说,它有一个非常重要的性质:它是一种绝对平衡的树。什么是绝对平衡,就是从根节点到任意一个叶子节点所经过的节点数量一定是相同的。

那 2-3 树是使用什么机制来维护绝对平衡的呢?


二、2-3 树如何维护绝对的平衡

下面我们来看看 2-3 树在做插入操作种是怎么样维护绝对平衡的。

(1) 首先我们向一颗空树中,插入一个节点 42,很显然,节点 42 将作为这棵 2-3 树的根节点。
在这里插入图片描述

(2) 之后我们再向 2-3 树种插入一个节点 37,如果按照二叉搜索树的插入方式,那么节点 37 应该插入在 42 的左子树中。但是 2-3 树并非如此。这里,需要记住一个很重要的点:在 2-3 树中插入一个节点,永远不会插入在空节点中。在后面,我将反复强调这一点。如果不添加到一个空的位置,那新的节点添加在哪呢?对于节点 42 来说,我们依然按照二分搜索树的性质来看,由于 37 小于 42,所以应该放在 42 的左子树中,但是由于 42 的左子树为空,那么此时,我们的新结点将融合到在添加过程中找到的最后一个叶子节点上,而这个叶子节点,就是节点 42。现在,我们整棵树就只有一个节点,42 既是根节点也是叶子节点。所以就会产生节点的融合,如下图所示:
在这里插入图片描述
  由于 42 本来是个 2 节点,融合了 37 之后,变成了一个 3 节点。那么,很显然,这棵 2-3 树,依然是平衡的。

(3) 我们继续往这棵树中添加一个节点 12,由于 12 比 37 小,应该添加到 37 的左子树中,但是由于 37 的左子树为空,上面我已经强调过,节点永远不会插入在一个空的位置上。只会和我们最后找到的叶子节点作融合。那么,我们最后找到的叶子节点是 37 和 42,虽然它现在是个 3 节点,但是我们依然先将节点 12 与之融合。暂时先形成这样一个 4 节点。
在这里插入图片描述
  因为 2-3 树最多只能 3 节点,对于 4 节点,我们可以很容易将其进行分裂。分裂成如下图所示:
在这里插入图片描述
  我们的一个4节点,通过分裂,形成了一个拥有 3 个2节点形成的 2-3 树。

(4) 如果在这棵树的基础上,我们继续添加一个节点 18。对于 18 来说,根节点是 37,所以 18 应该添加到 37 的左子树中,然后 18 与 12 比较,18 大于 12,应该添加在 12 的右子树中,但是 12 的右子树为空,所以 18 应该与 12 进行融合。此时,这棵树依然保持着平衡。
在这里插入图片描述

(5) 接下来,我们再来添加一个节点 6,6 比 12 小,6 应该添加到 12 的左子树中,12 的左子树为空,将6 与 12 暂时融合。形成 4 节点。
在这里插入图片描述
  之后对这个 4 节点进行拆解,如果按照第3步的拆解方式的话,那么这个数就会形成如下形状:
在这里插入图片描述
  那么,这棵树就不是一颗绝对平衡的树。对于2-3 树来说,一个叶子节点,如果它本身已经是一个 3 节点了,添加了一个新的节点,变成了一个 4 节点,那么我们将这个 4 节点拆成了上图形式之后,新形成的根节点 12 要向上面的父节点进行融合,那么 12 的父节点是 37,37 是一个2节点,可以很容易的进行融合。
在这里插入图片描述
此时的这棵 2-3 树才是一颗绝对平衡的树。

(6) 在添加一个节点 11,就很容易了,直接与节点 6 进行融合。
在这里插入图片描述

(7) 如果我们再来一个新结点 5,它首先与 6 和 11 进行融合,形成一个 4 节点,然后节点 6 向上与 12 和 37 做融合,又形成了一个 4 节点,然后继续将这个 4 节点进行分裂,最终,12 向上分裂,作为根节点。
在这里插入图片描述
  到此,一颗 2-3 树的插入过也就完成了。其实,我们上面演示的是一种很极端的情况,我们添加的第一个元素是整颗树种最大的元素,之后添加的元素都比第一个元素小。如果是二叉搜索树的话,那么早就非常偏斜了。但是对于 2-3 树而言,神奇的维护了这棵树的绝对平衡。


那么,下面我将对插入过程做一个总结:

  1. 如果插入到一个 2 节点中,很简单,直接融合即可。
    在这里插入图片描述
  1. 如果插入到一个 3 节点中,其实也并不难。
    在这里插入图片描述
    如果我们融合的这个 3节点是一个根节点,那么这个过程到此就结束了。可是,通常,我们融合的这个 3 节点并不是根节点,而是一个叶子节点,在这种情况下,同样也有两种情况。

(1)若这个4节点分裂出来形成的新的根节点(图上的节点4)它的父节点(节点6)为 2 节点,那么很简单,直接将这个根节点与它的父节点进行融合。
在这里插入图片描述

(2)若这个4节点分裂出来形成的新的根节点(图上的节点2)它的父节点为 3 节点,那么暂时将这个根节点与它的父节点进行融合。然后又形成了一个 4 节点,然后继续向上分裂,直到最终到达根节点。
在这里插入图片描述

三、红黑树与 2-3 树的等价性

  对于 2-3 树来说,它具有 2 节点和 3 节点。但是对于红黑树来说,它只有一个2节点,那么这两种树的节点之间时怎么等价的呢?

(1) 对于 2 节点来说,很简单,它本来就只有一个值,那么它也就对应红黑树中的一个节点。
在这里插入图片描述
(2) 但是对于 3 节点来说,就相对比较复杂一些,它对应红黑树的两个节点。而且 b和c两个节点是存在大小关系的,b < c,所以 b 一定在 c 的左边。所以在红黑树中,b 就应该是 c 的左孩子。但是现在为了方便观察,把b,c画成并列的。
在这里插入图片描述
  其实,它本应该是如下图所示:
在这里插入图片描述
  为了表示 b 和 c 这两个节点在原来的 2-3 树中是一个 3 节点,也就是它们本身在原来的 2-3 树中是放在一起的这样一种并列的关系,所以将 b 和 c 相连接的边绘制成红色。不过,我们之前所学习的二分搜索树对边这样的一个对象并没有相应的类来表示的,同样,在红黑树中,我们也没有必要对于每两个节点的边实现一个特殊的类来表示。可是,我们这个边又是红色的,那我们怎么表示这个特殊的颜色的边呢?

  答案非常简单。可以想象一下,每一个节点它只有一个父节点,换句话说,每一个节点与它父节点相连的边只有一条,我们可以把这条边的信息存放在节点上,换句话说,我们把 b 这个节点做一个特殊的标识,比如,让它变成红色的。其实,在这种情况下,就表示 b 这个节点和它父节点是相连的。
在这里插入图片描述
  由此,我们应该可以理解了,红黑树和 2-3 树是怎样等价的。实际上,我们进行了一个特殊的定义,在二分搜索树上,我们引入了红色这样的特殊的属性,而红色即表示该节点和其父节点一起是原来的 2-3 树中的一个 3 节点。那么,现在,我们的这个二分搜索树相当于就有两种节点了,一种节点是黑节点(普通节点),一种节点是红节点。所以这种树就叫做红黑树。我们也可以很容易得出一个结论,在红黑树中,所有的红色节点都是向左倾斜的。其实这个结论是我们定义出来的,而不是推导出来的。那是因为对于一个 3 节点来说,我们选择如上图所示的方式来表示。它会将 3 节点左边的那个元素当作右边这个元素的左孩子来看待,与此同时,左边的这个孩子是一个红色的节点。所以,红色的节点一定是向左倾斜的。

  那么,现在,我们可以看一颗比较复杂的树了,如下图所示,这是一颗 2-3 树。
在这里插入图片描述
  那么,这棵 2-3 树所对应的红黑树是什么样子的呢?
在这里插入图片描述
  对于这样的一个 2-3 树来说,它有 3 个红色节点。这是因为在原来的 2-3 树中,存在 三个 3 节点,这三个 3 节点左边的那个节点都将变成右边节点的左孩子,并且是红色的。

如果你觉得看上面的红黑树有点费劲的话,你可以把这棵红黑树想象成如下样子:
在这里插入图片描述
  那么通过这样的例子,想必更深刻的理解了为什么说红黑树和 2-3 树是这样的一个等价的关系。这是因为对于任意的一颗 2-3 树来说,我们都可以使用这样的规则把它转化成一颗红黑树。而且,这个转化的过程其实是非常简单的。


四、红黑树的基本性质和复杂度分析

我们再来回顾一下《算法导论》中红黑树的性质:

  1. 每个节点或者是红色的,或者是黑色的
  2. 根节点是黑色的
  3. 每一个叶子节点(最后的空节点)是黑色的
  4. 如果一个节点是红色的,那么它的孩子节点是黑色的
  5. 从任意一个节点到叶子节点,经过的黑色节点个数是一样的。
  1. 对于第一点,每个节点或者是红色的,或者是黑色的。这本来就是红黑树的定义,没有什么可解释的。

  2. 第二点,它的根节点一定是黑色的。由于我们说红黑树和 2-3 树是等价的,相应的,在 2-3 树中,对应的这个根节点要么是个 2 节点,要么是个 3 节点。而 2 节点和 3 节点在红黑树的表示如下,很容易看出,无论是哪种情况,根节点都是黑色的。
    在这里插入图片描述

  3. 第三条性质:每一个叶子节点(**最后的空节点**)是黑色的这里的叶子节点指的是空节点,而不是左右子树都为空的那个节点。相当于我们定义,在红黑树中,一个空节点的颜色是黑色的。其实这条性质也与第二条性质相呼应。对于一个空树而言,它也是一颗红黑树。它的根节点为空,所以这棵红黑树的根节点为黑色,与第二条性质相呼应。

  4. 如果一个节点是红色的,那么它的孩子节点是黑色的。可以想象一下,在红黑树中,什么情况下会出现红色的节点,那就是在原来的 2-3 树中存在一个 3 节点,那么这个红色节点的孩子会是怎样的呢?
    在这里插入图片描述
      其实这个红色节点的孩子就是在原来的 2-3 树中对应的左孩子或者是中间的孩子。这两个孩子要么是一个 2 节点,要么是一个 3 节点。如果它连接的是一个 2 节点,很显然,一个 2 节点在红黑树中就是一个黑色的节点,此时,这个红色的节点的孩子一定是个黑色的节点。如果它连接的是一个 3 节点,那么最后这个3节点转换成红黑树中就是一个黑色的节点加一个红色的节点,但是先连接的一定是黑色的节点。所以,有了第四条性质。
    在这里插入图片描述
    但是,大家注意,这个节点对于黑色节点来说,是不成立的。而黑色的节点它的右孩子一定是黑色的

  5. 第五条性质是红黑树中最最最重要的,这条性质几乎是红黑树的一个核心。从任意一个节点到叶子节点,经过的黑色节点个数是一样的。还是得从 2-3 树说起,2-3 树是一种绝对平衡的树,一颗绝对平衡的树意味着什么?意味着从 2-3 树中的任意一个节点出发到所有叶子节点所经过的节点数是相等的。那么,这个性质对应到红黑树中,就意味着经过的黑色节点是一样多的。这是因为在 2-3 树中,不论是 2 节点还是 3 节点,相应的转换成红黑树中的节点表示的时候,都会有一个黑色的节点,所以我们从红黑树的任意一个结点出发,每经过一个黑色的节点,就意味着经过原来的 2-3 树中的一个节点。区别就是,如果还经过了一个红色节点的话,就相当于经过了原来 2-3 树中的 3 节点。所以,我们通常说,红黑树是保持 ”黑平衡“ 的二叉树。严格意义讲,不是平衡二叉树

时间复杂度
对于一个拥有 n 个节点的红黑树而言,它的最大高度是 2logn。可以想象一种极端情况,从根节点出发,我们可能经过了 logn 个黑色节点,并且每一个黑色节点的左孩子都是红色节点。换句话说,这条路径上都是 3 节点。因为又有了 logn 个红色节点,所以这棵树的高度最高是 2logn。但是 2 是个常数,所以 它的高度还是 logn 级别的。换句话说,我们在一棵红黑树中查找一个元素的时间复杂度为 O(logn),我们不管是修改,添加和删除,我们都得先找到这个元素,所以时间复杂度都是 O(logn),但是一颗 AVL 树,它的高度是 logn,所以红黑树的查找效率可能会次于 AVL 树。

  所以,如果存储的数据要经常进行添加和删除的话,使用红色树是一种比较好的方法。但是,对于存储的数据近乎是不会变动的话,主要的操作就是查询的话,其实 AVL 树的性能会高一点。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值