红黑树定义
红黑树是一种二叉查找树,具有如下性质:
- 1.节点是红色或黑色
- 2. 根是黑色
- 3. 所有叶子都是黑色(叶子是NIL节点)
- 4. 如果一个节点是红的,则它的两个儿子都是黑的
- 5. 从任一节点到其叶子的所有简单路径都包含相同数目的黑色节点(黑色节点平衡)
- 6. 新插入节点为红色
红黑树应用
- C++的STL,map和set都是用红黑树实现的。
- 著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块。
- epoll在内核中的实现,用红黑树管理事件块。
- nginx用红黑树管理timer等。
- Java的TreeMap实现。
红黑树操作
插入节点
步骤一:插入
红黑树首先是一棵二叉排序树,根据二叉排序树的插入原则插入到相关位置,并设置成红色。
步骤二:调整
若插入节点的父节点为黑色,满足红黑树的性质,不用调整。
若父节点为红色,分为以下情况讨论:
1.父节点和叔叔节点均为红色
将父节点和叔叔节点均为红色设置为黑色,将爷爷节点从黑色变为红色(根据性质4,爷爷节点一开始肯定为黑色)。此时爷爷节点变成红色,可能其父节点为红色,违反性质4,需要递归调整(将爷爷节点的父节点和叔叔节点设置为黑色……,直到调整到根节点)。如插入和调整步骤图1和图2所示:
图1
图2
2.叔叔节点为黑色
需要分4种情况讨论:
(1)父节点为爷爷节点的右节点、插入节点为父节点的右节点(父右子右)
(2)父节点为爷爷节点的左节点、插入节点为父节点的左节点(父左子左)
(3)父节点为爷爷节点的右节点、插入节点为父节点的左节点(父右子左)
(4)父节点为爷爷节点的左节点、插入节点为父节点的右节点(父左子右)
父右子右:首先将父节点变成黑色子节点变成红色,然后以父节点为中心的左旋,如图3;
父左子左:首先将父节点变成黑色子节点变成红色,然后以父节点为中心的右旋;
父右子左可以通过以插入节点为中心的右旋变成父右子右,如图4;
父左子右可以通过以插入节点为中心的左旋变成父左子左。
图3
图4
删除节点
对于一棵二叉搜索树来说,删除的节点情况可以分为3种:
1.叶子节点
2.只有左子树或只有右子树的节点
3.既有左子树又有右子树的节点。对于一棵普通二叉树的情况3来说,要删除既有左子树又有右子树的节点,我们首先要找到该节点的直接后继节点,然后用后继节点替换该节点,最后按1或2中的方法删除后继节点即可。
对于红黑树来说,针对待删节点的颜色,需要分两种情况讨论:
(1)待删节点为红色
1.删除红色叶子节点
红色节点的删除不会打破红黑树的平衡,所以可以直接删除。
2.删除红色节点只有左子树或右子树
红色节点的子节点只能为黑色节点,这种情况不存在,违反了性质5(左子节点和右子节点的黑高差1)。
3.删除红色节点既有左子树又有右子树
若后继节点为红色,用该节点替换待删节点,最后按情况1删除后继节点。
若后继节点为黑色,见后续。
(2)待删除节点为黑色
1.删除的黑色节点仅有左子树或者仅有右子树
这两种情况的处理方式是一样的,即用D的孩子(左或右)替换D,并将D孩子的颜色改成黑色即可(因为路径上少了一个黑节点,所已将红节点变成黑节点以保持红黑树的性质)。
图5
2. 删除黑色的叶子节点
2.1黑色叶子节点的兄弟节点为红色
将其转变为兄弟节点为黑色的情况:若待删除黑色节点为左节点则以父节点P为中心左旋;若待删除黑色节点为右节点则以父节点P为中心右旋。
图6
图7
2.2黑色叶子节点的兄弟节点为黑色
2.2.1兄弟节点为黑色,侄子节点为红色
需要分4种情况讨论:
(1)兄节点为右节点、侄子节点为兄节点的右节点(兄右侄右)
(2)兄节点为左节点、侄子节点为兄节点的左节点(兄左侄左)
(3)兄节点为右节点、侄子节点为兄节点的左节点(兄右侄左)
(4)兄节点为左节点、侄子节点为兄节点的右节点(兄左侄右)
兄右侄右:以兄节点为中心左旋,兄节点变成父节点的颜色,父节点和侄子节点变黑,删除待删节点
图8
兄左侄左:以兄节点为中心右旋,兄节点变成父节点的颜色,父节点和侄子节点变黑,删除待删节点
图9
兄右侄左:以侄子节点为中心右旋变成兄右侄右
图10
兄左侄右:以侄子节点为中心左旋变成兄左侄左
图11
2.2.2兄弟节点为黑色,侄子节点为黑色
分两种情况:
(1)父节点为红色
(2)父节点为黑色
父节点为红色时,只需将父节点变黑、兄节点变红,然后删除待删节点
图12
父节点为黑色
方法是将兄弟节点S的颜色改成红色,这样删除D后P的左右两支的黑节点数就相等了,但是经过P的路径上的黑色节点数会少1,这个时候,我们再以P为起始点,继续根据情况进行平衡操作(这句话的意思就是把P当成D(只是不要再删除P了),再看是那种情况,再进行对应的调整,这样一直向上,直到新的起始点为根节点)。结果如图13。
举例:如图14,删除节点5,按2.2.2步骤将15变红,此时节点10之后的分支黑高少了1,所以需要对节点10进行调整。节点10的兄弟节点50为黑色,侄子节点60为红色,可以按照2.2.1以50为中心左旋,同时将节点60涂黑,这样红黑树又平衡了。
图13
图14