红黑树

红黑树的性质

  • 性质1:每个节点要么是黑色,要么是红色。
  • 性质2:根节点是黑色。
  • 性质3:每个叶子节点(NIL)是黑色。
  • 性质4:每个红色结点的两个子结点一定都是黑色。
  • 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。


红黑树的添加

我们可以把红黑树看成是一个四阶b树来理解。对于添加来说,最后的节点一定

红 红黑 黑黑 这四种,

如果添加到黑节点的话,不用操作

添加到红色节点的话,又分为添加到 黑红 红黑 和 红黑红两种

如果添加到红黑红的话,把黑色节点提到父节点上,然后递归调用add方法

如果是添加到红黑上面的话,就可通过旋转来完成

protected void afterAdd(Node<E> node) {
        
        Node<E> parent = node.parent;

        if(parent == null){ //如果父节点是空的话,说明此节点是根节点
            black(node);
            return;
        }

        if(isBlack(parent)) return;//这是只有黑的请况,不需要处理

        Node<E> uncle = node.sibling();
        Node<E> grand = parent.parent;
        
        if(isRed(uncle)){//这是红黑红的情况,此时节点已有3个元素,再添加一个就上溢了,把黑节点变成红色提到父节点上去
            //然后把其他节点拆开,红色节点都变成红色。父节点上有可能又会发生上溢,所以需要递归
            black(parent);
            black(uncle);
            red(grand);
            afterAdd(grand);
            return;
        }
        
        //这是红黑 或者黑红的情况,根据添加顺序的不同,分别进行旋转调节.
        //分为左左 , 右右 , 左右 , 右左
        //分别进行右旋转 , 左旋转 , 左右旋转 , 右左旋转
        if(parent.isLeftChild()){
            if(node.isLeftChild()){
                rotateRight(grand);
                red(grand);
                black(parent);
            }else{
                rotateLeft(parent);
                rotateRight(grand);
                black(node);
                red(grand);
            }
        }else{
            if(node.isLeftChild()){
                rotateRight(parent);
                rotateLeft(grand);
                red(grand);
                black(node);
            }else{
                rotateLeft(grand);
                red(grand);
                black(parent);
            }
        }
    }

红黑树的删除

删除分为3种情况,

当删除含有两个子节点的节点时,其实删的是这个节点的前驱或后继节点,所以被删除的元素一定是在4阶b树的最后一层上,也就是 红黑红 黑红 红黑 黑四种情况

当删除的是红色元素时,不会影响红黑树的结构,

当删除的是红黑红的黑色节点时,其实删除的是它的两个红色子节点中的一个。

当删除的 红黑 或黑红的黑色节点时,只需要把红色节点变成黑色就行.

当删除的是黑色节点时,就需要分多种情况了:

  1.如果这个黑色叶子节点的兄弟节点是黑色的话

    1.如果这个节点有红色子节点的话,通过旋转达到

    2.如果没有红色子节点的话,就把父节点下溢.

  2.如果兄弟节点时红色的话,就把红色节点的子节点当做是被删节点的兄弟节点,因此又回到了情况1.

    public void afterRemove(Node<E> node, Node<E> replacement) {
        Node<E> parent = node.parent;
        
        if(isRed(node)) return; //如果删除的是红色子节点,直接返回

        if(isRed(replacement)){//如果删除的是 红黑 和 黑红的情况 , 直接把红色子节点变成黑色
            black(replacement);
            return;
        }

        if(parent == null) return; //如果此节点是根节点,直接返回

        boolean left = parent.left == null || node.isLeftChild(); //判断删除的是左节点还是有节点
        
        Node<E> sibling = left ? parent.right : parent.left; //被删除节点的兄弟节点
        if(left){
            //被删除的是左边节点
            //操作与被删除右边是对称的
        }else{
            //被删除的是右边节点
            if(isRed(sibling)){//如果它的兄弟节点是红色的话,通过右旋转父节点让红色节点的子节点变成被删的兄弟节点
                black(sibling);
                red(parent);
                rotateRight(parent);
                //更新兄弟节点
                sibling = parent.left;
            }

            //如果兄弟节点没有红色子节点的话,把父节点下移,如果父节点是黑色的话,需要递归
            if(isBlack(sibling.left) && isBlack(sibling.right)) {
                boolean parentBlack = isBlack(parent);
                black(parent);
                red(sibling);
                if (parentBlack) {
                    afterRemove(parent, null);
                }

            }else{//兄弟节点至少有一个红色子节点通过旋转达到目的,需要把sibling的颜色变成父节点的颜色
                if(isBlack(sibling.left)){
                    rotateLeft(sibling);
                    sibling = parent.left;
                }

                color(sibling,colorOf(parent));
                black(parent);
                black(sibling.left);
                rotateRight(parent);
            }
        }

    }
原文地址:https://www.cnblogs.com/lzh66/p/12976482.html