关键特点:
1、根是黑色
2、NULL是黑色
3、没有相连的红色
4、一个节点到NULL所有路径上所有黑色节点数量相等
最高高度2log(N+1),最坏时间复杂度log(N)
插入:
自底向上插入:
需要用一个栈保存搜索路径经历过的节点。
1、按照二叉搜索树插入,新插入点为红色。
2、如果新插入节点的父亲是黑色,直接返回。
3、如果新插入的节点父亲是红色,分两种情况(需要一个处理函数):
A、新插入节点的叔叔是黑色的,直接旋转、涂色后返回。
旋转分两种情况:
a、祖父、父亲和当前节点呈“一”字形,单旋转,以祖父为支点,将父亲旋转到祖父处形成新的子树。
b、祖父、父亲和当前节点呈“之”字形,双旋转,以父亲为支点,将当前点旋转到父亲处,再以祖父为支点,将当前节点旋转到祖父处,形成新的子树。
涂色:
无论哪种情况,旋转完,将子树的根涂黑,子树的两个儿子涂红,之后就完成插入。
B、新插入节点的叔叔是红色的,此时将祖父涂成红色,父亲与叔叔涂成黑色,之后将祖父作为新插入节点,再次调用该处理函数。
当然,如果该节点是根,那么直接涂成黑色。
自顶向下插入:
自定向下插入需要保证下一个需要插入的节点是黑色的,以便在其后面插入。我们对二叉树搜索的同时进行红黑树的调整。
下一节点的情况:
1、如果下一个经过的节点是黑色的,无需处理,继续搜索。
2、如果下一个经过的节点是红色的,其兄弟也是红色的,也就是如果发现当前有两个红儿子,当前节点直接与两个儿子颜色翻转,之后再判断当前节点的父亲:
如果父亲是红色的,则以当前节点的祖父为根,进行如“自底向上插入”中情况3的两种旋转,并染色。之后走到“下一个要经过的节点”。
如果父亲是黑色,则继续向下搜索;
3、如果下一个经过的节点是红色,其兄弟是黑色,继续往下查找。唯一可能出现矛盾的是刚好在这个红色节点后面增加一个新节点,我们只要保证增加新节点之后,进行第2点中,判断当前节点父亲的颜色并进行相应的操作即可。
自顶向下删除:
自定向下删除与自顶向下插入的思想差不多,要保证下一个遇到的节点是红色,以便直接删除。
搜索开始前将根变红,根儿子变黑;
当前节点为红色,由于当前节点是红色,其儿子肯定都是黑色;
1、下一个有两个黑儿子,这是要看下一个节点的兄弟。
A、兄弟也是两个黑儿子,则直接进行颜色翻转。
B、兄弟有红儿子,则根据“父亲-兄弟-兄弟红儿子”的形状,进行单旋转或者双旋转。(如果有两个儿子,则两种旋转都可以)旋转后当前节点和子树的根染成红色,子树的两个儿子染成黑色。
2、下一节点有红儿子,假设往下走两步. (因为最终需要删除的节点绝对是两个NULL黑儿子,所以这个节点自然不会被删除)
A、如果刚好走到红儿子,自然不用处理,所以直接走到该位置。
B、如果刚好走到黑儿子,此时节点的父亲肯定是黑色,兄弟肯定是红色,进行兄弟与父亲的旋转,这样这个”下一个节点“就变成红色的了,然后继续往下走一步。