插入操作
- 插入空树,done
- 父节点为黑色,done
- 父节点为红色,看叔节点:
1. 叔节点为黑色时,通过单旋(zig-zig)或者双旋(zig-zag)变成一个4-node
2. 叔节点为红色时,通过变色修正,最后祖父节点变为红色,若再出现双红,则递归解决(如果递归到根,则需要把根节点染黑)
top-down的插入则是从上到下拆开4-node,避免3-2情况出现。
删除操作
如果被删除的节点是叶子节点,用null代替这个节点;
如果被删除的节点只有一个孩子,用它的孩子代替它;
如果被删除的节点有两个孩子,则用它的直接后继代替它,然后删除它的直接后继(它的直接后继最多只有一个孩子)。
现在如果我们真正被删除的节点y是红色的,那么删除它(用它的唯一孩子或null替代它);
如果我们真正被删除的节点y是黑色的,那么删除它后,它的子树x的黑高会减小1,需要修复。
修复的方式分为5种情况,我们称代替y的子节点为x,我们需要使得x的子树前面多一个黑色节点:
- 如果x为红色,则把x染黑,结束。
- 否则
- 如果x的兄弟为红色,旋转x的兄弟,使得x的兄弟为黑色(x兄弟的两个孩子都不为null,使得之后x的兄弟也不为null)。
- 如果x的兄弟为黑色:
- 如果x的兄弟有两个黑儿子,染红x的兄弟(在x和x原来父亲都为黑时,x的兄弟一定不为null),x=x.parent,循环.
- 如果x的兄弟靠近x的儿子为红,远的为黑,则旋转x的兄弟,使得x兄弟远离x的儿子为红。
- 如果x的兄弟远离x的儿子为红色,旋转x的兄弟,结束。
top-down的删除则是从上到下保证被删的叶子节点为红色。
顺便吐槽一句,《Algorithms》这本书里面的左倾红黑树看似简单,但是它递归的使用非常的tricky,特别是删除操作,所以反而不如《算法导论》中写的最朴素的bottom-up红黑树好理解。至于《数据结构与算法分析:java语言描述》中写的top-down红黑树,也挺好理解的,可惜缺了删除的代码。