1.红黑树的意义
[1]二叉查找树在极端的插入情况下,操作时间复杂度会变为O(n),但是*衡二叉树可以一直维持在O(lg(n))。因此*衡二叉查找树的效率很高,红黑树是一种自*衡二叉查找树的实现方式,这便是红黑树的意义。
2.红黑树性质
[1]节点是红色或黑色。
[2]根节点是黑色。
[3]每个叶节点(NIL节点,空节点)是黑色的。
[4]每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
[5]从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
3.变色、左旋和右旋
[1]变色, 目的是进行操作后可以(更趋*于)保持红黑树的性质。
[2]左旋和右旋是变更节点在树中的位置,目的是进行这些操作后可以(更趋*于)保持红黑树的性质。
4.删除操作
红黑树的删除和二叉查找树的删除操作是一样的,只是多了一个修复*衡的流程。
整体流程:首先按照二叉查找树的方式删除节点。之后判断释放节点的颜色,如果是红色,则结束,否则进入修复流程,修复流程就是一个状态机,直到走到完成状态。
[1]按照二叉查找树的删除流程:
[3]修复(状态机),循环执行以下操作:
1)如果当前节点是红色,则把当前节点涂黑,操作结束。
2)如果当前节点是黑色,且兄弟节点是红色,则进行操作:兄弟节点涂黑,父节点涂红,对父节点进行左旋。(此时,当前节点的父节点没变,但是兄弟节点变为黑色)。
3)如果当前节点是黑色,且兄弟节点是黑色,且兄弟节点的两个子节点都是黑色,则进行操作:兄弟节点涂红,将父节点作为当前节点(附带的操作就是更新父节点为之前节点的祖父节点)。
4)如果当前节点是黑色,且兄弟节点是黑色,且兄弟节点的右子节点是黑左子节点是红,则进行操作:兄弟节点涂红,兄弟左子节点涂黑,对兄弟节点进行右旋。(此时,当前节点的父节点没变,但是兄弟节点的右子节点变为红色)。
5)如果当前节点是黑色,且兄弟节点是黑色,且兄弟节点的右子节点是红左子节点任意,则进行操作:兄弟节点的颜色涂成父节点的颜色,父节点涂黑,兄弟节点的右子节点涂黑,对父节点进行左旋,将根节点涂黑,操作结束。
以上是当前节点是父节点左子节点的情况,如果是右子节点,只是做了对称处理(例如,对某个状态,作为左子节点时做左旋,而作为右子节点做右旋)。
5.插入操作
红黑树的删除和二叉查找树的插入操作是一样的,只是多了一个修复*衡的流程。
整体流程:首先按照二叉查找树的方式插入节点,把插入节点涂红。之后进入修复流程,修复流程就是一个状态机,直到走到完成状态。最后把根节点涂黑。
[1]按照二叉查找树的插入流程:小于根的往左子树递归插入,否则往右子树递归插入。插入的节点必定是插到最下面那一层,不会插入到树的中间位置。
初始把刚插入的节点涂红(涂红不会影响规则5,因此只需要处理更少的条件),把刚插入的节点作为当前节点。
[2]修复(状态机),循环执行以下操作:
1)如果当前节点的父节点是空,状态机完成。
2)如果当前节点的父节点是黑色,状态机完成。
3)如果当前节点的父节点是红色,叔叔节点是红色,则执行操作:将当前节点的父节点涂黑,叔叔节点涂黑,祖父节点涂红,再将祖父节点作为当前节点。
4)如果当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右子节点,则执行操作:对当前节点的父节点执行左旋,并把当前节点的父节点作为当前节点(附带更新当前节点的父节点(就是之前的节点))。
5)如果当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左子节点,则执行操作:对当前节点的父节点涂黑,祖父节点涂红,对祖父节点执行右旋。
最后把根节点涂黑,结束。
以上是当前节点是父节点左子节点的情况,如果是右子节点,只是做了对称处理(例如,对某个状态,作为左子节点时做左旋,而作为右子节点做右旋)。
6.总结
[1]红黑树的插入和删除和二叉查找树的方式是一样的,之后多了一个修复流程,主要就是修复流程的状态机,对于某一个状态来说,需要进行一系列的操作,进行这个操作的目的是为了进入下一个状态,下一个状态肯定更趋*于树的*衡。
[2]关于变色、左旋和右旋,这些操作的目的是为了让树的当前状态更趋于*衡,这个也是处理红黑树的关键,即什么时候需要变色、旋转,为何变色、旋转后可以更趋*于*衡,这个也需要在实践中熟练。
[3]对于插入修复状态机的第4个状态说明:"对当前节点的父节点执行左旋",这个操作结束后,当前节点和父节点的位置会互换,因此把父节点作为当前节点后,当前节点的父节点就是之前的节点,代码就是:
register struct rb_node *tmp; __rb_rotate_left(parent, root); //对父节点左旋 tmp = parent; // parent = node; //父节点作为当前节点,同时更新当前节点的父节点 node = tmp; //
[4]代码,参照linux内核红黑树源码。