【Java】红黑树简介插入操作s代码实现

一、红黑树的特点:
红黑树的和根节点必须为黑色,叶子节点也必须为黑色;红黑树连续的两层不能出现连续红色节点;在从每个父节点到叶子节点的简单路径上必须有个数相同个黑色节点。
二、红黑树的插入操作概述:
红黑树的插入首先和二叉树的插入一样,要先判断把节点放在哪个子树,然后在进行旋转操作。
当树为空时,插入的节点即为根节点,设成黑色;
当树不为空时,插入的节点应为红色,如果它的父节点为黑色,插入成功;如果父节点为红色,则要进行调整操作。

插入调整(看叔叔):
首先,插入的调整是为了保证红黑树每个子树黑色节点一样多的这一性质。根据这个思路,分为如下三个请况(以下均从左子树边进行插入,右子树同理):
1、父节点红色,叔叔红色:将叔叔和父亲都变成黑色,爷爷节点变成红色,指针指向爷爷,继续向上回溯。(如果爷爷已经是根节点了,直接将爷爷变红)。
2、父亲节点为红色,叔叔是黑色:交换父亲和爷爷的颜色,然后以爷爷为根节点进行右旋;
3、插入节点和爷爷父亲不在一顺侧:先以父节点为根节点进行左旋,然后再右旋;
代码实现:
插入代码:

private void insert(T data){
    if(this.root==null){
       this.root=new RBNode<>(data,null,null,null,Color.BLACK);
    }
    RBNode<T> cur=this.root;
    RBNode<T> parent=null;
    while (cur!=null){
        if(cur.getData().compareTo(data)>0){//当前值比插入的值大
            parent=cur;
            cur=cur.getLeft();
        }if (cur.getData().compareTo(data)<0){
            parent=cur;
            cur=cur.getRight();
        }else {
            return;
        }
    }
    RBNode<T> node =new RBNode<>(data,null,null,parent,Color.RED);
    if(parent.getData().compareTo(data)>0){
        parent.setLeft(node);
    }
    if(parent.getData().compareTo(data)<0){
        parent.setRight(node);
    }
    if(color(parent) == Color.RED){
        fixAfterInsert(node);
    }

}

左旋右旋代码:

private void leftRotate(RBNode<T> node){
    RBNode<T> child = node.getRight();//定义孩子   1
    child.setParent(node.getParent());//改变孩子的父节点
    if(node.getParent() == null){//node本来就是根节点时
        this.root = child;//当前的节点直接设为
    } else {//node不是根节点时
        if(node.getParent().getLeft() == node){//当node为父节点的左孩子
            node.getParent().setLeft(child);//把node父节点的左孩子射程child
        } else {//node我i父节点的右孩子
            node.getParent().setRight(child);//把node 父节点的有孩子设成child
        }
    }
    node.setRight(child.getLeft());//node的右孩子时child树为左孩子   2
    if(child.getLeft() != null){//如果child有左孩子(防止空指针访问)
        child.getLeft().setParent(node);//child的左孩子的父设置成node
    }
    child.setLeft(node);//node为child的左孩子   3
    node.setParent(child);//node的父节点为child
}
private void rightRotate(RBNode<T> node){
//    RBNode<T> child=node.getLeft();
//
//    node.setLeft(child.getRight());
//
//    child.setRight(node);
        RBNode<T> child=node.getLeft();
        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.setLeft(child.getRight());
       if(child.getRight()!=null){
           child.getRight().setParent(node);
       }
        child.setRight(node);
        node.setParent(child);
    }

插入调整代码:

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:爸爸是红色,叔叔是红色,叔父都变成黑色,爷爷变成红色,x指向爷爷,继续向上遍历
                setColor(parent(node), Color.BLACK);
                setColor(uncle, Color.BLACK);
                setColor(parent(parent(node)), Color.RED);
                node = parent(parent(node));//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.RED);
                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);// 有可能向上回溯到根节点跳出,把根节点置成黑色
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值