红黑树的操作(一)

2 篇文章 0 订阅
1 篇文章 0 订阅

      红黑树的介绍

            红黑树的定义:(Red Black Tree)是一种自平衡二叉查找树,能在进行删除和插入操作时通过特定操作保持二叉查找树的平             衡,从而获得较高的查找性能。

 

      红黑树的特点:

          1、红黑树是一颗平衡树

          2、红黑树节点左右子树的高度差为:长的不能超过短的2倍,这样就牺牲掉了一些平衡,但是提高了删除和插入操作的效率。

          

          * 红黑树的增删查效率高于AVL树

          *(旋转次数少很多,但是有节点重新着色)   

 

          3、红黑树插入最多旋转两次,删除最多旋转三次

      红黑树的性质:

             (1)每个节点都有颜色,不是黑色,就是红色

             (2)叶子结点(left和right)是黑色(null) null是黑色

             (3)根节点root必须是黑色

             (4)不能出现连续的红色节点

             (5)从根节点root到达每一个叶子结点的路径上,黑色节点的数量都是相同的

 

      红黑树的节点插入:(具体来说就是插入后调整的三种)                                                                                                                              1、插入前树是空的,则新插入的根节点必须为黑色

             2、插入前树不为空,则新插入的节点应该是红色的,然后检查父亲(parent)节点,如果父亲节点是黑色就插入完成;

              如果父亲节点不是黑色就要做插入调整;

             当父亲节点为红色时的情况:                                                                                                                          

      情况一:parent节点的兄弟节点为红色(此时先将parent节点和parent节点的兄弟节点同时置为黑色,然后将     parent.parent节点置为红色,然后判断parent.parent节点是否有parent节点,有的话判断它的兄弟节点的颜色,然后重复前面的操作,如果parent.parent节点没有父亲节点,就直接将parent节点置为黑色就完成了)                                                                                                             

               B.Color = Black;

               C.color = Black;                                                                                                                                                             

               parent.parent = Red;

               X = parent.parent;

       情况二:  parent节点的兄弟节点为黑色,同时新插入的节点、插入节点的parent节点、parent.parent节点在同一侧(先将parent节点的颜色和parent.parent节点的颜色互换,然后以parent.parent节点为根节点右旋)

      

           parent.color = Black;

           parent.parent.color = Red;

           rightRotate(parent.parent);

      情况三:parent节点的兄弟节点为黑色,同时新插入的节点、插入节点的parent节点、parent.parent节点不在同一侧(先以parent节点为根节点左旋,然后按照情况二的操作进行调整)

        leftRotate(parent);

        parent.color = Black;

        parent.parent.color = Red;

        rightRotate(parent.parent);

     

 红黑树的插入代码:

public void insert(T data) {
   //先判断树是否为空
    if(root == null) {
        this.root = new Node(data,null,null,null,Color.BLACK);
        return;
    }
   //遍历的方向
     RBNode<T> cur = this.root;
     RBNode<T> parent = null;
     while(cur != null) {
        if(cur.getData().compareTo(data) > 0) {
            cur = cur.getLeft();
        }else if(cur.getData().compareTo() < 0){
            cur = cur.getRight();
        } else{
            return;
        }
    
    }
//插入的节点
    RBNode<T> node = new RBNode<T>(data,null,null,null,Color.RED);
    if(parent.getData().compareTo(data) > 0) {
        parent.setLeft(node);
    }else{
        parent.setRight(node);
    }

    if(color(parent(node)) == Color.BLACK) {
        fixAfterInsert(node);
    }
}
    private void fixAfterInsert(RBNode<T> node) {
        while(color(parent(node)) == Color.RED) {
             if (left(parent(parent(node))) == parent(node)) {
                    //当前节点,父节点在祖先节点的左子树
                    RBNode<T> uncle = right(parent(parent(node)));
             if (color(uncle) == Color.RED) {  //插入情况1
                    setColor(parent(node), Color.BLACK);
                    setColor(uncle, Color.BLACK);
                    setColor(parent(parent(node)), Color.RED);
                    node = parent(parent(node));
             }else{
                if (node == right(parent(node))){  // 插入情况3前半段
                            node = parent(node);
                            leftRotate(node);
                }
        setColor(parent(node),Color.BLACK);
                        // 插入情况3后半段和情况2合并

                        setColor(parent(parent(node)),Color.BLACK);
                        rightRotate(parent(parent(node)));
                        break;
                    }
                } else {
                    // 当前节点,父节点在祖先节点的右树
                    RBNode<T> uncle = left(parent(parent(node)));
                    if(color(uncle) == Color.RED){ // 插入情况1
                        setColor(parent(node), Color.BLACK);
                        setColor(uncle, Color.BLACK);
                        setColor(parent(parent(node)), Color.RED);
                        node = parent(parent(node));
                    } else {
                        if(node == left(parent(node))){ // 插入情况3前半段
                            node = parent(node);
                            rightRotate(node);
                        }

                        setColor(parent(node), Color.BLACK); // 插入情况3后半段和情况2合并
                        setColor(parent(parent(node)), Color.RED);
                        leftRotate(parent(parent(node)));
                        break;
                    }
                }
            }
            // 有可能向上回溯到根节点跳出,把根节点置成黑色
            setColor(this.root, Color.BLACK);
        }


    private void leftRotate(RBNode<T> node){
        RBNode<T> child = node.getRight();
        child.setParent(node.getParent());
        if(node.getParent() == null){
            this.root = child;
        } else {
            if(node.getParent().getLeft() == node){
                node.getParent().setLeft(child);
            } else {
                node.getParent().setRight(child);
            }
        }

        node.setRight(child.getLeft());
        if(child.getLeft() != null){
            child.getLeft().setParent(node);
        }

        child.setLeft(node);
        node.setParent(child);
    }

    private void rightRotate(RBNode<T> node){
        RBNode<T> child = node.getLeft();
        child.setParent(node.getParent());
        if(node.getParent() == null) {
            this.root = child;
        }
        node.setLeft(child.getRight());

        child.setRight(node);
    }

}
}

 

                                                                                                                                                                      

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值