本文内容
- 红黑树的概念
- 红黑树新增节点的分析
- 红黑树删除节点,戳这里【图解红黑树】删除居然这么简单?假的吧?
开篇故事
小A是个程序猿,最近工作压力大,头发都快变地中海了。今天下班的地铁上路遇小C,见他头发茂盛,遂想打听打听小C平时怎么保养的。
小A:“哥们儿,打听个事儿呗。”
小C玩手机中,头都不抬:“啥事啊?”
“就是…”小A本想问头发,却发现小C屏幕上闪过二叉树、排序、遍历等字样,出口的话立马变成:“你也是程序猿?”
“不是。”小C抬头,露出一个狡黠的笑容,“我是攻城狮”。
“哦。”小A看清楚了,对方手机屏幕上分明写着java算法与程序,心想:小样,大家都叫程序猿,偏偏你要叫攻城狮。
难得路遇同行,正好切磋切磋,头发什么的,往后再说。
小A:“流弊啊兄弟,攻城狮听起来就比程序猿高大上。我考考你?”并丢出一个挑衅的眼神。
小C扶了一下眼镜:“说。”
小A:“知道红黑树吗?”
小C:“自然。”
小C正准备发表长篇大论,旁边抱孙子的老婆婆不干了,她拍了拍小C,颤颤巍巍的说:“小伙子,我知道那枫树是红的,柳树是绿的,秋天的银杏是黄的。你那红黑树是啥树?又红又黑的?上面结出来滴是人参果?”
二叉查找树
学习红黑树之前,先了解一下二叉查找树,下图就是一颗二叉查找树。
二叉查找树满足条件:每一个节点都大于他的左子节点,并且小于他的右子节点。
二叉查找树的查找时间复杂度介于O(Log2n)到O(n)之间,从上图中的结构看,似乎一切正常,查找效率接近二分查找,看起来效率不低。
但实际情况往往不会那样理想,比如下面这种情况:
二叉查找树一条腿长,一条腿短,像一个瘸子,此时整棵树的查找效率极低,为O(n)。因为这颗二叉查找树失去了平衡。
基于以上的问题,我们需要一种机制,使二叉查找树保持平衡状态。而红黑树,就能够自动调节,使其自身保持在平衡状态,算法的时间复杂度为O(Log2n)。
红黑树
红黑树的五个性质:
- 1.节点是红色或者黑色
- 2.根节点是黑色
- 3.每个叶子节点是黑色的(NIL节点也叫空节点)
- 4.不存在两个连续的红色节点(黑色节点可以连续)
- 5.从根节点出发,到任意一个叶子节点(NIL),都包含相同数量的黑色节点
取一张图,作为参照理解,可对照上述五条逐一查看:
理清基本概念,现在来看为了满足五条特性,红黑树是怎么调整的。
本篇主要是写新增节点,删除节点写在下一篇。
方法有二:变色和自旋。
新增的情况不外乎几种:
1.新增根节点,插入后变为黑色。极简单。
2.新增节点的父节点是红色。
2-1. 如果叔节点是红色。
将父和叔节点标位黑色 -> 将祖节点变成红色 -> 将新增节点的颜色变成与祖节点一致 -> 根据调整结果,重复2-1 或者2-2
话不多说,直接上图:
上图2和4的两张图片相同,是因为示例给出的红黑树过于简单,恰好祖节点是根节点时才会出现这种情况。
动图,查看10和5插入的过程:
如果叔节点是红色,首先考虑变色;但如果叔节点是黑色,首先考虑旋转。
先了解一下旋转的基本方式,附两张动图:
左旋
右旋
2-2. 如果叔节点是黑色,分为四种情况处理
No.1
父节点是祖节点的左子节点,新增节点是父节点的左子节点(文字读起来绕,看图)
这种情况的处理:想象有一只手,拎起父节点,然后再变色。
No.2
父节点是祖节点的左子节点,新增节点是父节点的右子节点(看图)
固定处理方式:
第一步,左旋。左旋后的结果,就是NO.1的情况。
第二步,再应用NO.1 处理方式。
还记得左旋吗?再回顾一下动图。
左旋动图
第一步 左旋
第二步 重复NO.1 处理
NO.3
父节点是祖节点的右子节点,新增节点是父节点的右子节点(与NO.1相反 看图)
如果看明白了NO.1和NO.2两种情况,那么NO.3和NO.4就很容易理解了。
同样用一只大手,把父节点拎起来,然后变色。
NO.4
父节点是祖节点的右子节点,新增节点是父节点的左子节点(与NO.2相反 看图)
第一步,右旋。
第二步,处理方式同NO.3,还记得从天而降的大手吗?没错,用大手拎起来。
复习一下右旋:
接下来上过程图:
右旋
一只大手拎起来:
至此,红黑树新增图解完成,下一篇将介绍红黑树删除 【图解红黑树】删除居然这么简单?假的吧?。
推荐一个工具网站:
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
上面的动图,就是在该网站录制。
上图列出了一些简单的功能说明。
To be continued… …