文章目录
声明: 红黑树的所有叶子节点都是黑色(此处提到的叶子其实是空链接,因篇幅问题全文未画出)
1. 2-3-4树
1. 2-3-4树和红黑树的关系
红黑树的本质其实也是对2-3-4树1的一种实现:
- 红黑树概念中两个左右红色节点A,C是其父亲节点B(必为黑色)在2-3-4树概念中的兄弟索引(即A,B,C为一个B树结点的3个关键字)。
- 从边的角度理解:黑点->红点的边是表示B树中同一个节点的索引,黑点->红点、红点->黑点的边都表示B树节点的数据指针指向下一个节点。
- 由此可以把一颗红黑树还原成一颗2-3-4树。
2. 红黑树
2.1 概念
一棵红黑树满足如下性质:
- 节点是红色或黑色;
- 所有路径上不能有两个连续的红色节点;
- 根节点必须为黑色;
- 从任一节点到其子树中的每个叶子的所有简单路径上都包含相同数目的黑色节点2。(黑高平衡)
- 红黑树的叶子节点都是空结点,且都为黑色,在此处不画出(??哪里来的我想问)。
2.2 左偏红黑树(Left Leaning Red Black Tree)
左偏红黑树是一种容易实现的红黑树变体。
与普通的红黑树不同的是,在左偏红黑树中,是边具有颜色而不是节点具有颜色。我们习惯用一个节点的颜色代指它的父亲边的颜色。(这个性质在理解层面好像没什么用)。
左偏红黑树对红黑树进行了进一步限制,一个黑色节点的左右儿子:要么全是黑色;要么左儿子是红色,右儿子是黑色。
注:由于黑色节点没有右红儿子,所以红偏红黑树是2-3树而非2-3-4树(无有3个键,4个子节点的节点)。所以当一个节点有三个键(对应红黑树中一个黑色节点有两个红色儿子时)就应该分裂一下了。
符合条件的情况:
不符合条件的情况:
这是左偏树的「左偏」性质:红色边只能是左偏的。
2.3 旋转操作
树的旋转操作看别的博文吧,在此不赘述。
2.4 插入操作(左倾红黑树)
这一部分最值得思考的就是用B树的角度去看待红黑树的染色问题。
说明:
- 插入时都是插入红色节点(才能不违反黑高平衡)。
- 要系统、更有条理地分类这部分插入操作,请看2.5插入操作部分。
一些比较简单的插入:
- 插入根节点需要染黑(否则遇到红节点左红儿子时无法旋转——我自己的理解)。
- 插入黑父的左儿子直接插入就行,所以也不作讨论。
- 插入黑父的右儿子,黑父的左儿子没有,直接把右儿子旋转成黑父的父亲就行,所以也不作讨论。
对于左倾红黑树的插入,值得讨论的一共有三种情况:
- 第一种,待插入元素比黑父大,插在了黑父的右边,而黑父左边是红色儿子。这种情况会导致在红黑树中出现右倾红节点。
注意,这种情况对应着2-3树中出现了临时4节点,我们在2-3树中的处理是将这个临时4节点分裂,左右元素各自形成一个2节点,中间元素上升到上层跟父节点结合。所以,我们在红黑树中的动作是,将原本红色的左右儿子染黑(左右分裂),将黑父染红(等待上升结合)。
第二种情况,待插入元素比红父小,且红父自身就是左倾。
这种情况我们需要用两步来调整:首先对红父的父亲进行一次右旋(光是右旋节点没换颜色,破坏了黑色平衡),接下来将12所在节点与15所在节点交换颜色(其实这两步应该是同步进行的,看下面2-3树思想部分)。
之后我们得到了情况1的场景,直接按情况1处理。
用2-3树思想,3个键已经需要分裂了,分裂时应该找中间的节点顶上去(即12),所以才会把12旋成父节点并且变成黑色(预备被顶),并且在之后变成红色(被顶上去了)。
第三种情况,待插入元素比红父大,且红父自身就是左倾。
也就是说插入的这个节点形成了一个右倾的红色节点,对右倾的处理很简单,将红父进行一次左旋,就能使得右倾红节点变为左倾,现在出现了连续的左倾红节点,直接按情况2处理即可。
本博文参考总结+搬运了以下大佬博文4,侵删。
2.5 插入操作
请参考以下大佬博文5,写得超级清楚了。