【数据结构】手撕红黑树!--java实现

一、红黑树特性回顾

红黑树通过以下规则维护平衡:

  1. 节点颜色非红即黑
    2.根节点必黑
    3.叶子节点(NIL)视为黑
    4.红节点不能有红子节点(红红不相邻)
    5.任意路径黑节点数相同

二、核心代码解析

      1. 节点结构定义

enum Color{ RED, BLACK } // 颜色枚举

static class Node {
    int key;             // 节点键值
    Object value;        // 存储数据
    Node left, right;    // 左右子节点
    Node parent;         // 父节点指针
    Color color = Color.RED; // 默认红色
    
      //判断是不是左孩子
        boolean isLeftChild() {
            return parent != null && parent.left==this;
        }

        //返回叔叔节点
        Node uncle(){
            if(parent==null||parent.parent==null) return null;

            if(parent.isLeftChild()) {
                return parent.parent.right;
            }else {
                return parent.parent.left;
            }
        }

        //返回兄弟节点
        Node subling(){
            if(parent==null){
                return null;
            }
            if(this.isLeftChild()){
                return parent.right;
            }else {
                return parent.left;
            }
        }
}

2. 旋转操作

平衡树结构的关键操作,分为左旋和右旋:

//右旋
    private void rightRotate(Node node){
        Node parent = node.parent;
        Node node1 =node.left;
        Node node2 =node.right;
        if(node2!=null){
            node2.parent = node;
        }
        node1.right=node;
        node1.parent=node.parent;
        node.left=node2;
        node.parent=node1;
        if(parent==null){
            root = node1;
        }
        if(parent.left==node){
            parent.left=node1;
        }else {
            parent.right=node1;
        }
    }

    //左旋
    private void leftRotate(Node node){
        Node parent = node.parent;
        Node node1=node.right;
        Node node2=node1.left;
        node1.left=node;
        node.right=node2;
        node.parent=node1;
        if(node2!=null){
            node2.parent=node;
        }
        if(parent==null){
            root = node1;
        }
        if(parent.left==node){
            parent.left=node1;
        }else {
            parent.right=node1;
        }
    }

3、判断节点颜色


    boolean isRed(Node node){
        return node!=null&& node.color==Color.RED;
    }

    boolean isBlack(Node node){
        return !isRed(node);
    }

4、插入操作

插入后通过颜色调整维持平衡

  void put(int key,Object value){
        Node p=root;
        Node parent = null;
        while(p!=null){
            parent=p;
            if(p.keykey){
                p=p.left;
            }else {
                p.value=value;
                return;
            }
        }
        Node inserted=new Node(key,value);
        if(parent==null){
            root = inserted;
        }
        if (parent.key>key){
            parent.left=inserted;
            inserted.parent=parent;
        }else {
            parent.right=inserted;
            inserted.parent=parent;
        }
        fixRedRed(inserted);
    }

5. 插入修复逻辑

当出现连续红节点时进行平衡调整:

void fixRedRed(Node node){

        //插入节点为根节点,将根节点变成黑色。
        if(node==root){
            node.color=Color.BLACK;
            return;
        }

        //插入节点的父亲节点为黑色,不必调整。
        if(isBlack(node.parent)){
            return;
        }

        //执行到这里,说明node既不是根节点,而且父亲节点是红色。
        //红红相邻
        Node parent=node.parent;
        Node uncle=node.uncle();
        Node grandparent=parent.parent;
        //叔叔为红
        if(isRed(uncle)){
            node.parent.color=Color.BLACK;
            uncle.color=Color.BLACK;
            grandparent.color=Color.RED;
            fixRedRed(grandparent);
            return;
        }

        //执行到这里,就说明叔叔为黑色。
        //LL
        if(parent.isLeftChild()&& node.isLeftChild()){
            parent.color=Color.BLACK;
            grandparent.color=Color.RED;
            rightRotate(grandparent);
        //LR
        }else if(parent.isLeftChild()&&!node.isLeftChild()){
            leftRotate(parent);
            node.color=Color.BLACK;
            grandparent.color=Color.RED;
            rightRotate(grandparent);
        //RR
        }else if(!parent.isLeftChild()&&!node.isLeftChild()){
            parent.color=Color.BLACK;
            grandparent.color=Color.RED;
            leftRotate(grandparent);
        //RL
        }else {
            rightRotate(parent);
            node.color=Color.BLACK;
            grandparent.color=Color.RED;
            leftRotate(grandparent);
        }


    }

6. 删除操作

public void remove(int key) {
    Node deleted = find(key);
    if (deleted == null) return;
    doRemove(deleted); // 执行实际删除
}

查找删除节点,以及替换节点 


    //查找删除节点
    Node find(int key){
        Node p=root;
        while(p!=null){
            if(p.key>key){
                p=p.left;
            }else if(p.key

 删除主逻辑:

 private void doRemove(Node deleted){
        Node replace=findReplaced(deleted);
        Node parent=deleted.parent;
        if(replace==null){
            if(deleted==root){
                root=null;
            }else {
                if(isBlack(deleted)){
            //删除节点时,可能会发生节点颜色失衡,违反第五条规则,调用修复方法:
                    fixBlackBlack(deleted);
                }
                if(deleted.isLeftChild()){
                    parent.left=null;
                }else {
                parent.right=null;
                }
                deleted.parent=null;
            }
            return;
        }
        //有一个孩子
        if(deleted.left==null||deleted.right==null){
            if(deleted==root){

                root=replace;
                replace.parent=null;
            }else {
                if(deleted.isLeftChild()){
                    parent.left=replace;
                }else {
                    parent.right=replace;
                }
                    replace.parent=parent;

                if(isBlack(deleted)&&isBlack(replace)){
                    fixBlackBlack(replace);
                }else {
                    replace.color=Color.BLACK;
                }

            }
            deleted.left=deleted.right=null;
            return;
        }
        //执行到这里,说明deleted有两个孩子。
        int t=deleted.key;
        deleted.key=replace.key;
        replace.key=t;

        Object v=deleted.value;
        deleted.value=replace.value;
        replace.value=v;
        doRemove(replace);
    }

双黑颜色调整:

private void fixBlackBlack(Node x){
        if(x==root){
            return;
        }

        Node parent=x.parent;
        Node sibling=x.subling();
        //当兄弟是红色
        if(isRed(sibling)){
            if(x.isLeftChild()){
                leftRotate(parent);
            }else {
                rightRotate(parent);
            }
            parent.color=Color.RED;
            sibling.color=Color.BLACK;
            fixBlackBlack(x);
        }

        if(sibling != null){
            //兄弟是黑色,两个侄子也是黑色
            if(isBlack(sibling.left)&&isBlack(sibling.right)){
                sibling.color=Color.RED;
                if(isRed(parent)){
                    parent.color=Color.BLACK;
                }else {
                    fixBlackBlack(parent);
                }
                //兄弟是黑色,至少有一个侄子是红色
            }else{
                if(sibling.isLeftChild()&&isRed(sibling.left)){
                    rightRotate(parent);
                    sibling.left.color=Color.BLACK;
                    sibling.color=sibling.parent.color;
                    parent.color=Color.BLACK;
                }
                else if(sibling.isLeftChild()&&isRed(sibling.right)){
                    sibling.right.color=parent.color;
                    leftRotate(sibling);
                    rightRotate(parent);
                    parent.color=Color.BLACK;
                }
                else if(!sibling.isLeftChild()&&isRed(sibling.left)){
                    sibling.left.color=parent.color;
                    rightRotate(parent);
                    leftRotate(parent);
                }
                else {
                    leftRotate(parent);
                    sibling.right.color=Color.BLACK;
                    sibling.color=sibling.parent.color;
                    parent.color=Color.BLACK;
                }
            }
        }else{
            fixBlackBlack(parent);
        }
    }

你可能感兴趣的:(数据结构,java,前端)