数据结构&算法之《红黑树》

为什么会有红黑树?


二叉搜索树是一个很不错的数据结构,正常情况下可以很快速的查找,删除和添加元素,但是在某些情况下它会变得很糟糕,比如,插入的元素是有序的,那么二叉搜索树就变成了只有左子树或者只有右子树的怪物,实际上就变成了链表结构,像这种平衡度很差的搜索二叉树的执行效率就变得很差。

为了能高效的搜索一颗二叉搜索树,就要保证树本身是平衡的(或者大致平衡),这里的平衡说的是树的左边的后代数目和右边的后代数目大致相同。而我们要说的红黑树就是这样的平衡二叉树。

对于每一个要插入的节点,红黑树的插入程序都会检查会不会破坏树的特征结构,如果结构被破坏了,程序就会修正,根据需要改变树的结构,来保证树的平衡。

红黑树的特质


1.红黑树的每个节点不是红色就是黑色(其实就是一个标志位而已)
2.根节点一定是黑色的
3.如果节点是红色的,那么它的子节点必须是黑色的, 反之则不一定
4.从根节点到叶子节点的每条路径上,必须包含相同数目的黑色节点

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


在红黑树中新插入的节点总是红色的,这不是随随便便拍大腿决定的;因为插入黑色节点一定会违背红黑树特质[4](因为一条路径上多了一个黑色节点),而插入红色节点则只有一半的机会违背红黑树特质[3] (如果新节点的父节点是红色,就违背了特质[3]),并且先人们说了,违背特质[3]比违背特质[4]更容易修正。

节点之间的关系

在开始下面的内容之前,我们要先明白节点和节点之间的关系,因为后面的内容中会用到这些关系术语,这里,我们用一张图来表示:


节点关系图

这里,以节点[12]为例子,它的一些长辈和晚辈如下:
1.左孩子和右孩子: [11][13]
2.兄弟: [18]
3.近侄子: [16]; 远侄子: [19]; 这里的远近相信大家能判断出来。比如[18]的近侄子就是[13],远侄子就是[11]
4.父亲: [14]
5.叔叔: [2]
6.祖父: [10]

红黑树的平衡性修正


红黑树平衡性修正的方法只有三种:变色、左旋和右旋

1.变色
变色很简单,其实主要是新插入的红色节点的父节点是红色节点(违背了红色节点的子节点必须是黑色节点的特质),只需要修改父节点的颜色即可

2.左旋 && 右旋
例如,有这样一棵树,我们以节点[2]为支点进行左旋:

左旋

过程是这样的:1.将节点[7]的左孩子[5]转接到节点[2]的右孩子上;2.将节点[2]的父节点[11]变成节点[7]的父节点;3. 将节点[2]转接到节点[7]的左孩子上

右旋则正好相反,比如:以节点[7]为支点进行右旋:

右旋

过程是这样的:1.将节点[2]的右节点[5]转接到节点[7]的左孩子上;2.将节点[7]的父节点[11]变成节点[2]的父节点;3.将节点[7]转接到节点[2]的右孩子上。

这里对红黑树进行左旋和右旋的原因,主要是为了调整红黑树的平衡度

红-黑树的插入图解


红黑树的插入可以分解为这么几个步骤:

1: 插入的是第一个节点,直接设为根节点,变成黑色即可,不需要修正
2: 插入节点的父节点是黑色的(因为插入的红色节点不违背每条路径上黑色节点数相同这一特质),不需要修正
3: 插入节点的父节点是红色;(因为插入的红色节点违背了红色节点下必须是黑色节点这一特质),所以这种情况都需要修正
3.1:叔叔节点是红色;修正过程如下:
    1. 将父节点和叔叔节点变黑
    2.将祖父节点变红 *
    3.将祖父节点设为当前节点,然后对新的当前节点重新修正
3.2:叔叔节点是黑色;又分下面几种情况
    3.2.1:当前节点是父亲的左孩子,父亲是祖父的左孩子;修正过程如下:
      
1.以祖父为支点右旋 *
      2.交换父亲和祖父的颜色
    3.2.2: 当前节点是父亲的右孩子,父亲是祖父的左孩子;修正过程如下:
      1.以父亲为支点左旋 *
      
2.将父亲设为当前节点重新修正*
    3.2.3: 当前节点是父亲的右孩子,父亲是祖父的右孩子;修正过程如下:
      1.以祖父为支点左旋 *
      
2.交换父亲和祖父的颜色*
    3.2.4: 当前节点是父亲的左孩子,父亲是祖父的右孩子
      1.以父亲为支点右旋 *
      
2.将父亲设为当前节点重新修正*

下面我们用图形来展示下插入的修正过程:


插入修正过程

这里展示了绝大部分的情况,只要按照每种情况下的修正原则来修正就可以了。

红黑树的删除图解


删除节点这里要分两部分来处理

1. 节点交换

如果直接将节点在原位置删除的话,需要考虑删除节点的左右子树的嫁接问题,有点麻烦;另外一种方法是将要删除的节点和它的最小后继或者最大前继交换,然后再删除,本章节中,我们采用交换最小后继的方式,比如,下面这样:


交换最小后继

注意,这里交换的只是节点的值,不要交换节点的颜色;另外,交换的话还有几种情况,我们要把要删除的节点一直交换到叶子节点为止,所以要循环去交换直到完成。

情况1. 当前节点没有孩子,是叶子节点
   1. 节点是红色的,直接删除即可
   2. 节点是黑色的,删除后违背红黑树特质,需要做后面的变色旋转修正处理,然后再删除
情况2. 当前节点有两个孩子节点;
   则从后继节点中找到最小后继D, 交换当前节点和节点D的值,然后把原节点D作为当前节点重新走交换节点流程
情况3. 当前节点只有左孩子L;
   交换当前节点和L节点的值,然后把原L节点作为当前节点重新走交换节点流程
情况4. 当前节点只有右孩子R;
   交换当前节点和R节点的值,让后把原R节点作为当前节点重新走交换节点流程

经过上面的处理,我们就把要删除的节点移位到了叶子节点;剩下要做的就是处理情况1中的第2种情况中的变色旋转

2. 变色旋转

为了后续方便,我们用下面的简称来代表节点之间的关系 (节点之间的关系我们在上面已经描述过了,不记得的可以往上翻一翻):
P: 当前节点的父节点
W: 当前节点的兄弟节点
Nf: 当前节点的远侄子
Nn: 当前节点的近侄子

情况1:当前节点是根节点或者是红色节点
   直接将其变成黑色,变色旋转结束;
情况2:W是红色
   则将W设为黑色,P设为红色,对P进行旋转(当前节点是P的左节点时,左旋,当前节点是P的右节点时右旋);然后再重新进行旋转变色
情况3:W是黑色,且它的两个孩子也是黑色
   则将w设为红色,将P设为当前节点,重新进行旋转变色
情况4:W是黑色,Nf是红色
   则将W设为P的颜色,P和Nf设为黑色,并对P进行旋转(当前节点是P的左孩子就左旋,是右孩子就右旋),变色旋转结束;
情况4:W是黑色,Nf是黑色
   则交换W和Nn的颜色,并对W进行旋转(当前节点是P的左孩子则右旋,是右孩子则左旋),然后重新进行旋转变色;

下面是一个删除示例:


删除图示

具体的代码实现

iOS demo


自从工作之后,感觉算法用到的场景很少,大部分都是底层用的比较多,实际业务中用的比较少,导致一些基本的数据结构和算法都忘记了,再者由于现在面试中都喜欢面试数据结构和算法,也算是未雨绸缪吧,接下来准备把常用的基本数据结构和算法全都重新复习一遍。

最后,感谢几位大神的文章解惑:
【数据结构和算法05】 红-黑树
红黑树原理以及插入、删除算法 附图例说明

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351