红黑树

二叉查找树

由于红黑树本质上就是一棵二叉查找树,所以在了解红黑树之前,咱们先来看下二叉查找树。

二叉查找树(Binary Search Tree),也称有序二叉树(ordered binary tree),排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:

  • 若任意结点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若任意结点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 任意结点的左、右子树也分别为二叉查找树。
  • 没有键值相等的结点(no duplicate nodes)。

因为,一棵由n个结点,随机构造的二叉查找树的高度为lgn,所以顺理成章,一般操作的执行时间为O(lgn).(至于n个结点的二叉树高度为lgn的证明,可参考算法导论 第12章 二叉查找树 第12.4节)。

但二叉树若退化成了一棵具有n个结点的线性链后,则此些操作最坏情况运行时间为O(n)。后面我们会看到一种基于二叉查找树-红黑树,它通过一些性质使得树相对平衡,使得最终查找、插入、删除的时间复杂度最坏情况下依然为O(lgn)。

红黑树

前面我们已经说过,红黑树,本质上来说就是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。

但它是如何保证一棵n个结点的红黑树的高度始终保持在h = logn的呢?

这就引出了红黑树的5条性质:
  1. 每个结点要么是红的,要么是黑的。
  2. 根结点是黑的。
  3. 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。
  4. 如果一个结点是红的,那么它的俩个儿子都是黑的。
  5. 对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。

正是红黑树的这5条性质,使得一棵n个结点是红黑树始终保持了logn的高度,从而也就解释了上面我们所说的“红黑树的查找、插入、删除的时间复杂度最坏为O(log n)”这一结论的原因。

如下图所示,即是一颗红黑树(下图引自wikipedia:http://t.cn/hgvH1l):
这里写图片描述

上文中我们所说的 “叶结点” 或”NULL结点”,它不包含数据而只充当树在此结束的指示,这些结点以及它们的父结点,在绘图中都会经常被省略。

树的旋转知识

当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质。

为了继续保持红黑树的性质,我们可以通过对结点进行重新着色,以及对树进行相关的旋转操作,即修改树中某些结点的颜色及指针结构,来达到对红黑树进行插入或删除结点等操作后,继续保持它的性质或平衡。

树的旋转,分为左旋和右旋,以下借助图来做形象的解释和介绍:
左旋:
这里写图片描述
右旋:
这里写图片描述

我们先明确一下各节点的叫法 :
这里写图片描述

插入:

因为要满足红黑树的这五条性质
如果我们插入的是黑色节点,那就违反了性质五,需要进行大规模调整
如果我们插入的是红色节点,那就只有在要插入节点的父节点也是红色的时候违反性质四或者是当插入的节点是根节点时,违反性质二
所以,我们把要插入的节点的颜色变成红色。

下面是可能遇到的插入的几种状况:

1、当插入的节点是根节点时,直接涂黑即可;
2、当要插入的节点的父节点是黑色的时候。
这里写图片描述
这个时候插入一个红色的节点并没有对这五个性质产生破坏。所以直接插入不用在进行调整操作。

3、如果要插入的节点的父节点是红色且父节点是祖父节点的左支的时候。
这个要分两种情况,一种是叔叔节点为黑的情况,一种是叔叔节点为红的情况。
当叔叔为黑时,也分为两种情况,一种是要插入的节点是父节点的左支,另一种是要插入的节点是父亲的右支。
3.1 我们先看一下当要插入的节点是父节点的左支的情况:
这里写图片描述
这样插入违反了性质4(红黑节点下的子节点必须是黑色的),我们就需要进行调整操作,使之符合性质四。
我们可以通过对祖父节点进行右旋同时将祖父节点和父节点的颜色进行互换,这样就变成了:
这里写图片描述

3.2 当要插入的节点是父节点的右支的时候,我们可以先对父节点进行左旋,变成如下:
这里写图片描述
如果我们把原先的父节点看做是新的要插入的节点,把原先要插入的节点看做是新的父节点,那就变成了当要插入的节点在父节点的左支的情况,对,是的,就是按照当要插入的节点在父节点的左支的情况进行旋转,旋转完之后变成如下:
这里写图片描述
4、如果要插入的节点的父节点是红色且父节点是祖父节点的右支的时候;
这个时候的情况跟情况3所表述的情况是一个镜像,将情况3的左和右互换一下就可以了。

5、如果要插入的节点的父节点是红色并且叔叔节点也为红色,如下:
这里写图片描述
这个时候,只需将父亲节点和叔叔节点涂黑。
以上就是插入的全部过程。

删除

下面我们再讲讲删除的操作:
首先你要了解普通二叉树的删除操作:
1.如果删除的是叶节点,可以直接删除;
2.如果被删除的元素有一个子节点,可以将子节点直接移到被删除元素的位置;
3.如果有两个子节点,这时候就可以把被删除元素的右支的最小节点(被删除元素右支的最左边的节点)和被删除元素互换,我们把被删除元素右支的最左边的节点称之为后继节点(后继元素),然后在根据情况1或者情况2进行操作。如图:
这里写图片描述

将被删除元素与其右支的最小元素互换,变成如下图所示:
这里写图片描述
然后再将被删除元素删除:
这里写图片描述

我们下面所称的被删除元素,皆是指已经互换之后的被删除元素。
加入颜色之后,被删除元素和后继元素互换只是值得互换,并不互换颜色,这个要注意。

下面开始讲一下红黑树删除的规则:
1.当被删除元素为红时,对五条性质没有什么影响,直接删除。
2.当被删除元素为黑且为根节点时,直接删除。
3.当被删除元素为黑,且有一个右子节点为红时,将右子节点涂黑放到被删除元素的位置,如图:

这里写图片描述
变成
这里写图片描述
4.当被删除元素为黑,且兄弟节点为黑,兄弟节点两个孩子也为黑,父节点为红,此时,交换兄弟节点与父节点的颜色;NIL元素是指每个叶节点都有两个空的,颜色为黑的NIL元素,需要他的时候就可以把它看成两个黑元素,不需要的时候可以忽视他。
如图:

这里写图片描述
便变成:
这里写图片描述
5.当被删除元素为黑、并且为父节点的左支,且兄弟颜色为黑,兄弟的右支为红色,这个时候需要交换兄弟与父亲的颜色,并把父亲涂黑、兄弟的右支涂黑,并以父节点为中心左转。如图:
由:
这里写图片描述
变成:
这里写图片描述
6.当被删除元素为黑、并且为父节点的左支,且兄弟颜色为黑,兄弟的左支为红色,这个时候需要先把兄弟与兄弟的左子节点颜色互换,进行右转,然后就变成了规则5一样了,在按照规则5进行旋转。如图:

这里写图片描述
先兄弟与兄弟的左子节点颜色互换,进行右转,变成:
这里写图片描述
然后在按照规则5进行旋转,变成:
这里写图片描述
7.当被删除元素为黑且为父元素的右支时,跟情况5.情况6 互为镜像。
8.被删除元素为黑且兄弟节点为黑,兄弟节点的孩子为黑,父亲为黑,这个时候需要将兄弟节点变为红,再把父亲看做那个被删除的元素(只是看做,实际上不删除),看看父亲符和哪一条删除规则,进行处理变化如图:
由:
这里写图片描述
变成:
这里写图片描述
9.当被删除的元素为黑,且为父元素的左支,兄弟节点为红色的时候,需要交换兄弟节点与父亲结点的颜色,以父亲结点进行左旋,就变成了情况4,在按照情况四进行操作即可,变化如下:
由:
这里写图片描述
交换兄弟节点与父亲结点的颜色,以父亲结点进行左旋 变成:
这里写图片描述
在按照情况四进行操作,变成:
这里写图片描述

总结:

好了,删除的步骤也讲完,没有讲到的一点就是,在添加删除的时候,时刻要记得更改根元素的颜色为黑。
这里并没有语言实现,只是讲了一下红黑树的插入删除步骤,你可以根据步骤自己把红黑树实现。
点击这里,照着规则一步一步的构建一个红黑树吧。
最后:
1.红黑树的实现其实是一个2、3、4树,只是将双节点或者三节点用红色进行了标示,如果你将红色节点放到和它父元素相同的高度,并把它和父元素看做是一个元素,你就会发现,变成了一个高度为lgN的二叉树,这个2.3.4树对红黑树很有启发意义。
2.上面的步骤其实可以不用死记硬背,是可以推导出来的,因为我们是把一个平衡但通过插入或者删除破坏了平衡的红黑树再次平衡,同过旋转让位,改变红黑颜色,使之符合那五条基本性质。比如遇到删除操作情况四的时候,我们可以把那个删除元素去除,发现左边比右边少一个黑元素,这个时候,怎么办,我们发现兄弟节点的子元素有一个红元素,操作这个不会影响那五条性质,所以我们通过变换颜色,旋转,即可让左右两边的的黑色数目一样。
3.旋转操作的目的是出让一个元素到另外的地方并且符合二叉树左小右大的性质,交换颜色的目的是为了保持红黑树的那五条性质。
4.要时刻记得 ,一切的操作都是为了保持那五条性质。

最后的最后,其实还有一种更为简单的红黑二叉树,这个简单的红黑二叉树实际上是一个2.3树,他只允许左节点为红节点,但是性能上肯定是不如这个红黑树。这个简单的红黑二叉树在《算法》第四版有介绍,掌握完之后再看这个简单的红黑二叉树,就会觉着简单 easy。
最后的最后的最后,一定要尝试着自己推导一下插入删除规则啊,不然经常忘,是睡一觉起来再看就有点懵逼的那种忘。

来源:最容易懂得红黑树

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值