数据结构-红黑树

红黑树

红黑树(英语:Red–black tree)是一种自平衡二叉查找树,典型的用途是实现关联数组。
它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的:它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。

红黑树和AVL树一样都对插入时间、删除时间和查找时间提供了最好可能的最坏情况担保。这不只是使它们在时间敏感的应用如实时应用(real time application)中有价值,而且 使它们有在提供最坏情况担保的其他数据结构中作为建造板块的价值;例如,在计算几何中使用的很多数据结构都可以基于红黑树。

红黑树在函数式编程中也特别有用,在这里它们是最常用的持久数据结构(persistent data structure)之一,它们用来构造关联数组和集合,每次插入、删除之后它们能保持为以前的版本。除了O(log n)的时间之外,红黑树的持久版本对每次插入或删除需要O(log n)的空间。

红黑树相对于AVL树来说,牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要优于AVL树。

红黑树性质

红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
1.节点是红色或黑色。
2.根是黑色。
3.所有叶子都是黑色(叶子是NIL节点)。
4.每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
5.从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

img
img

这些约束确保了红黑树的关键特性:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。

要知道为什么这些性质确保了这个结果,注意到性质4导致了路径不能有两个毗连的红色节点就足够了。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。

因为每一个红黑树也是一个特化的二叉查找树,因此红黑树上的只读操作与普通二叉查找树上的只读操作相同。然而,在红黑树上进行插入操作和删除操作会导致不再匹配红黑树的性质。恢复红黑树的性质需要少量(O(logn))的颜色变更(实际是非常快速的)和不超过三次树旋转(对于插入操作是两次)。虽然插入和删除很复杂,但操作时间仍可以保持为O(logn)次。

红黑树添加节点

将一个节点插入到红黑树中,需要执行哪些步骤呢?首先,将红黑树当作一颗二叉查找树,将节点插入;然后,将节点着色为红色;最后,通过"旋转和重新着色"等一系列操作来修正该树,使之重新成为一颗红黑树。详细描述如下:

第一步: 将红黑树当作一颗二叉查找树,将节点插入。
红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。此外,无论是左旋还是右旋,若旋转之前这棵树是二叉查找树,旋转之后它一定还是二叉查找树。这也就意味着,任何的旋转和重新着色操作,都不会改变它仍然是一颗二叉查找树的事实。
好吧?那接下来,我们就来想方设法的旋转以及重新着色,使这颗树重新成为红黑树!

第二步:将插入的节点着色为"红色"。
为什么着色成红色,而不是黑色呢?
(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色。
(3) 每个叶子节点是黑色。 (注意:这里叶子节点,是指为空的叶子节点!)
(4) 如果一个节点是红色的,则它的子节点必须是黑色的。
(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

将插入的节点着色为红色,不会违背"特性(5)"!少违背一条特性,就意味着我们需要处理的情况越少。

第三步: 通过一系列的旋转或着色等操作,使之重新成为一颗红黑树。
第二步中,将插入节点着色为"红色"之后,不会违背"特性(5)"。那它到底会违背哪些特性呢?
对于"特性(1)",显然不会违背了。因为我们已经将它涂成红色了。
对于"特性(2)",显然也不会违背。在第一步中,我们是将红黑树当作二叉查找树,然后执行的插入操作。而根据二叉查找数的特点,插入操作不会改变根节点。所以,根节点仍然是黑色。
对于"特性(3)",显然不会违背了。这里的叶子节点是指的空叶子节点,插入非空节点并不会对它们造成影响。
对于"特性(4)",是有可能违背的!

情形1:新节点N位于树的根上,没有父节点。在这种情形下,我们把它重绘为黑色以满足性质2。因为它在每个路径上对黑节点数目增加一,性质5匹配。

情形2:新节点的父节点P是黑色,所以性质4没有失效(新节点是红色的)。在这种情形下,树仍是有效的。性质5也未受到威胁,尽管新节点N有两个黑色叶子子节点;但由于新节点N是红色,通过它的每个子节点的路径就都有同通过它所替换的黑色的叶子的路径同样数目的黑色节点,所以依然满足这个性质。

情形3:如果父节点P和叔父节点U二者都是红色,(此时新插入节点N做为P的左子节点或右子节点都属于情形3,这里右图仅显示N做为P左子的情形)则我们可以将它们两个重绘为黑色并重绘祖父节点G为红色(用来保持性质5)。现在我们的新节点N有了一个黑色的父节点P。因为通过父节点P或叔父节点U的任何路径都必定通过祖父节点G,在这些路径上的黑节点数目没有改变。但是,红色的祖父节点G可能是根节点,这就违反了性质2,也有可能祖父节点G的父节点是红色的,这就违反了性质4。为了解决这个问题,我们在祖父节点G上递归地进行情形1的整个过程。(把G当成是新加入的节点进行各种情形的检查)

img
img

情形4:父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的右子节点而父节点P又是其父节点的左子节点。在这种情形下,我们进行一次左旋转调换新节点和其父节点的角色;接着,我们按情形5处理以前的父节点P以解决仍然失效的性质4。注意这个改变会导致某些路径通过它们以前不通过的新节点N(比如图中1号叶子节点)或不通过节点P(比如图中3号叶子节点),但由于这两个节点都是红色的,所以性质5仍有效。

img
img

情形5:父节点P是红色而叔父节点U是黑色或缺少,新节点N是其父节点的左子节点,而父节点P又是其父节点G的左子节点。在这种情形下,我们进行针对祖父节点G的一次右旋转;在旋转产生的树中,以前的父节点P现在是新节点N和以前的祖父节点G的父节点。我们知道以前的祖父节点G是黑色,否则父节点P就不可能是红色(如果P和G都是红色就违反了性质4,所以G必须是黑色)。我们切换以前的父节点P和祖父节点G的颜色,结果的树满足性质4。性质5也仍然保持满足,因为通过这三个节点中任何一个的所有路径以前都通过祖父节点G,现在它们都通过以前的父节点P。在各自的情形下,这都是三个节点中唯一的黑色节点。

img
img

红黑树删除节点

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

情形2: S是红色。在这种情形下我们在N的父亲上做左旋转,把红色兄弟转换成N的祖父,我们接着对调N的父亲和祖父的颜色。完成这两个操作后,尽管所有路径上黑色节点的数目没有改变,但现在N有了一个黑色的兄弟和一个红色的父亲(它的新兄弟是黑色因为它是红色S的一个儿子),所以我们可以接下去按情形4、情形5或情形6来处理。

img
img

情形3: N的父亲、S和S的儿子都是黑色的。在这种情形下,我们简单的重绘S为红色。结果是通过S的所有路径,它们就是以前不通过N的那些路径,都少了一个黑色节点。因为删除N的初始的父亲使通过N的所有路径少了一个黑色节点,这使事情都平衡了起来。但是,通过P的所有路径现在比不通过P的路径少了一个黑色节点,所以仍然违反性质5。要修正这个问题,我们要从情形1开始,在P上做重新平衡处理。

img
img

情形4: S和S的儿子都是黑色,但是N的父亲是红色。在这种情形下,我们简单的交换N的兄弟和父亲的颜色。这不影响不通过N的路径的黑色节点的数目,但是它在通过N的路径上对黑色节点数目增加了一,添补了在这些路径上删除的黑色节点。

img
img

情形5: S是黑色,S的左儿子是红色,S的右儿子是黑色,而N是它父亲的左儿子。在这种情形下我们在S上做右旋转,这样S的左儿子成为S的父亲和N的新兄弟。我们接着交换S和它的新父亲的颜色。所有路径仍有同样数目的黑色节点,但是现在N有了一个黑色兄弟,他的右儿子是红色的,所以我们进入了情形6。N和它的父亲都不受这个变换的影响。

img
img

情形6: S是黑色,S的右儿子是红色,而N是它父亲的左儿子。在这种情形下我们在N的父亲上做左旋转,这样S成为N的父亲(P)和S的右儿子的父亲。我们接着交换N的父亲和S的颜色,并使S的右儿子为黑色。子树在它的根上的仍是同样的颜色,所以性质3没有被违反。但是,N现在增加了一个黑色祖先:要么N的父亲变成黑色,要么它是黑色而S被增加为一个黑色祖父。所以,通过N的路径都增加了一个黑色节点。
此时,如果一个路径不通过N,则有两种可能性:

它通过N的新兄弟。那么它以前和现在都必定通过S和N的父亲,而它们只是交换了颜色。所以路径保持了同样数目的黑色节点。

它通过N的新叔父,S的右儿子。那么它以前通过S、S的父亲和S的右儿子,但是现在只通过S,它被假定为它以前的父亲的颜色,和S的右儿子,它被从红色改变为黑色。合成效果是这个路径通过了同样数目的黑色节点。

在任何情况下,在这些路径上的黑色节点数目都没有改变。所以我们恢复了性质4。在示意图中的白色节点可以是红色或黑色,但是在变换前后都必须指定相同的颜色。

img
img

--

红黑树本身也是一种近似2-3-4树的数据结构。
通常2-3-4树实现较红黑树而言相对复杂。

img
img

具体实现:
https://github.com/imstayreal/data-struct-study/tree/master/DataStruct/src/redblack

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

推荐阅读更多精彩内容

  • 这篇文章收录在我的 Github 上 algorithms-tutorial,另外记录了些算法题解,感兴趣的可以看...
    Lindz阅读 4,216评论 3 18
  • 1、红黑树介绍 红黑树又称R-B Tree,全称是Red-Black Tree,它是一种特殊的二叉查找树,红黑树的...
    文哥的学习日记阅读 9,761评论 1 35
  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 4,373评论 1 31
  • 基于树实现的数据结构,具有两个核心特征: 逻辑结构:数据元素之间具有层次关系; 数据运算:操作方法具有Log级的平...
    yhthu阅读 3,945评论 1 5
  • BST 二叉查找树(Binary Search Tree,简称BST)是一棵二叉树,它的左子节点的值比父节点的值要...
    小菜_charry阅读 326评论 0 1