对红黑树的插入处理,真正需要考虑的有以下几点:
1).插入位置:插入在外侧还是内侧。插入位置影响的是单次旋转是否足够使新树遵守红黑树规则,具体看下面分析。
2).伯父节点的颜色:伯父节点的颜色是红色还是黑色。红色时只要变换颜色即可处理,而黑色则需要进行旋转了。
3).曾祖父节点的颜色:曾祖父点的颜色是红色还是黑色。由于伯父节点是红色时,我们进行的是换色处理,如果曾祖父是红色,则新的矛盾点出现在了曾祖父节点和换色的节点之间,具体看下面分析。
情况一:伯父节点为黑色,且为外侧插入
首先说说插入位置的影响:
如果是外侧插入,以下图为例:
首先我们考虑,出现矛盾的是P与N的颜色均为红色,那简单一点直接把P变为黑色是不是就可以了呢?
这个想法是错误的,因为在N未插入之前,该RBTree是平衡的,也就是说P子树和U子树中黑色的节点应该相同,现在为了解决N与P的颜色问题而直接将P染色成黑色,等价于在P子树中新增了一个黑色节点,破坏了任意路径中黑色节点相同的规则,因此这是不可行的。
我们再考虑其他方式,首先,P与N是连着的,而我们的目的是在不破坏其他规则的情况下使他们异色,而直接变色已经证明是不可行的了,那我们的思路改变一下,如果让P节点不在处于P子树,也就是说在将P变色的情况下让他升高高度,这样在原来P高度及以下的黑色节点个数还是一样的(因为P是红色的,移动了也不会改变原来P子树中的黑色节点个数)。
因此我们效仿AVL树中的旋转操作,将G进行右旋,3子树并入G的左子树,则发现现在P的高度升高了。在按原定思路,改变P的颜色,现在N与P间已经没有问题了,但G由于降到右子树上,增加了右子树的黑色节点个数,但这很好处理,我们只要将G变为红色就行了。
情况一:伯父节点为黑色,且为内侧插入
我们在考虑内侧插入的影响:
如果是内侧插入,以下图为例:
直接换色我们已经在上面说过了,这是不可行的,那如果效仿外侧插入,提高P的高度在换色呢?
这也是不可行的,原因在于插入位置的变化。在上面我们看到,旋转后P的右子树会并入G的左子树上,在上面中,由于P是红色节点,因此它的右子树的根节点一定是黑色的,因此并过去无论G是什么颜色都不会出现红红的情况。
而现在可以看到,新插入的位置在内侧,且插入节点一定是红色的(如果插入节点为黑色,则相当于增加了一个黑色节点,破坏了黑色节点个数相同的规则),则并入G中后,会使N,G间又出现了同红色,且此时的N相对于G还是内侧插入,则如果仍这样处理N只会在左子树与右子树间跳来跳去而无法真正使红黑树平衡。
因此我们不能简单的单次旋转就解决问题,但我们发现,如果对P进行左旋,相当于直接演变为上述外侧插入的情况。
这样就很好处理了,首先将P左旋,化为上述外侧插入的情况,然后将G右旋,变色即可。
然后我们谈谈伯父节点的颜色问题:
首先对于伯父节点的颜色,上面的讨论其实已经把伯父节点为黑色的情况讨论了,我们只需要考虑伯父节点为红色的情况。
伯父节点为红色的处理其实很简单,以下图为例子:
出现问题在于P,N间呈现了红色同色,而如果我们只要将P与U全换色,然后将G也换色即可(为了维护黑色节点个数的平衡)。
但这种处理方式也会带来问题,问题在于我们将G的颜色转变为了红色。
这也就引入了影响因素3),也就是曾祖父节点的问题。
如果曾祖父节点为黑色,那一切好说,现在RBTree平衡了,但如果曾祖父节点为红色呢?
我们现在将NP同色的问题转换到了上一层的祖父G与N的曾祖父GG间的红色同色问题了,因此对NG间在进行前面已经说明的解决方式即可。