红黑树简单学习

红黑树分析

红黑树有五个性质:
性质1:节点是红色或黑色。
性质2:根节点是黑色。
性质3: 每个叶节点(NIL节点,空节点)是黑色的。
性质4: 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5: 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
三大核心操作:染色,左旋,右旋

插入情况分析:

  1. 父节点为null,则此节点为root

  2. 父节点为黑节点,直接插入

  3. 父节点为红,并且为爷爷节点的左子树,叔叔是红;

    将爸爸和叔叔染黑,爷爷染红,以爷爷为节点进行递归(此时爷爷以下已经完整,爷爷以上不完整,把爷爷当作新插入的红色节点)

  4. 父节点为红节点,并且为爷爷节点的左子树,叔叔是黑或者Null;

    1. 当前节点为父亲节点的左子树LL操作。
    2. 为右节点LR,先右旋就从LR变成了LL,再LL操作;
  5. 父节点为红节点,并且为爷爷节点的右子树,叔叔是黑或者Null;

    1. 当前节点为父亲节点的右子树RR操作。
    2. 当前节点为父亲节点的左子树RL操作。

LL 操作[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Nyl9yGr-1589376307157)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200513212238207.png)]

RR 同LL, RL 同LR;

/** 1. 创建RBTree, 定义颜色
 *  2. 创建RBNode
 *  3. 辅助方法: parentOf(node), isRed(node),isBlack(node) setRed(node), setBlack(node),inOrderPrint()
 *  4. 左旋方法: leftRotate(node)
 *  5. 右旋方法: rightRotate(node)
 *  6. 公开插入接口方法定义: insert(K key, V value);
 *  7. 内部插入接口方法定义: insert(RBNode node);
 *  8. 修正插入导致红黑树失衡方法定义: insertFIxUp(RBNode node);
 *  HashMap 底层是 链表+数组+红黑树
 * @param <K> 键
 * @param <V> 值
 */
public class RBTree<K extends Comparable<K>, V> {
    private static final boolean RED = true;
    private static final boolean BLACK = false;
    // 定义根
    private RBNode root;
    // 获取当前节点的父节点
    private RBNode parentOf(RBNode node){
        if(node != null){
            return node.parent;
        }
        return null;
    }
    // 判断节点是否为红色
    private boolean isRed(RBNode node){
        if(node != null){
            return node.color == RED;
        }
        return false;
    }

    // 设置节点为红色
    private void setRed(RBNode node){
        if(node != null){
            node.color = RED;
        }
    }
    // 设置节点为黑色
    private void setBlack(RBNode node){
        if(node != null){
            node.color = BLACK;
        }
    }

    // 判断节点是否为红色
    private boolean isBlack(RBNode node){
        if(node != null){
            return node.color == BLACK;
        }
        return false;
    }

    // 中序打印二叉树
    public void inOrderPrint(){
        inOrderPrint(this.root);
    }
    private void inOrderPrint(RBNode root){
        if(root != null){
            inOrderPrint(root.left);
            System.out.println("Key: " + root.key + ",value: " + root.value);
            inOrderPrint(root.right);
        }
    }


    // 左旋
    private void leftRotate(RBNode x){
        RBNode y = x.right;
        // 将x 的 右子节点 指向y的左子节点,并更新 y 做儿子的父亲为x
        x.right = y.left;
        if(y.left != null){
            y.left.parent = x;
        }
        // 当x 的父亲不为null时, 将 y 代替x
        if(x.parent != null){
            y.parent = x.parent;

            if(x == x.parent.left){
                x.parent.left = y;
            }else x.parent.right = y;
        }else{
            // 说明是根节点
            this.root = y;
            this.root.parent = null;
        }
        // 将x 变为 y的 左儿子
        x.parent = y;
        y.left = x;
    }
    // 右旋 , 同左旋
    private void rightRotate(RBNode y){
        RBNode x = y.left;
        y.left = x.right;
        if(x.right != null){
            x.right.parent = y;
        }
        if(y.parent != null){
            x.parent = y.parent;
            if(y == y.parent.left) y.parent.left = x;
            else y.parent.right = x;
        }else{
            this.root = x;
            this.root.parent = null;
        }
        x.right = y;
        y.parent = x;
    }

    // 公开的插入方法
    public void insert(K key, V value){
        RBNode node = new RBNode();
        node.setKey(key);
        node.setValue(value);
        // 新增节点一定是 红色
        node.setColor(RED);
        insert(node);
    }

    private void insert(RBNode node){
        RBNode parent = null;
        RBNode x = this.root;

        while(x != null){
            parent = x;
            // cmp 大于0 则 右子树,如果相等 则替换值,否则左子树
            int cmp = node.key.compareTo(x.key);
            if(cmp > 0){
                x = x.right;
            }else if(cmp == 0){
                x.setValue(node.getValue());
                return ;
            }else{
                x = x.left;
            }
        }


        node.parent = parent;
        // 判断 node 是否与 parent key 谁大
        if(parent != null){
            // 不会有等于的情况
            int cmp = node.key.compareTo(parent.key);
            if(cmp > 0){
                parent.right = node;
            }else {
                parent.left = node;
            }
        }else this.root = node;


        // 调用修复红黑树平衡方法
        insertFixUp(node);

    }

    // 修复红黑树平衡
    // |---- 1. 红黑树为空树 ---  将节点染黑
    // |---- 2. 插入节点的key已存在 --- 不用处理了
    // |---- 3. 插入节点的父节点为黑色  ---- 不用处理了

    // |---- 4. 插入节点的父节点为红色
    //          |--- 4.1 叔叔节点存在,且为红色 (父叔 双红) --- 将 爸爸也 叔叔染黑, 将爷爷节点染红,
    //          并且以爷爷为当前节点 进行下一步处理
    //          |--- 4.2 叔叔节点不存在,或者为黑色,父节点为爷爷节点的左子树
    //              |--- 4.2.1 ll 双红  ---- 染黑爸爸,染红爷爷,以爷爷为节点右旋
    //              |--- 4.2.2 lr 双红 --- 先以父亲为节点左旋 变成 ll,再同ll操作
    //          |--- 4.3 叔叔节点不存在,或者为黑色,父节点为爷爷节点的右子树
    //              |--- 4.3.1 rr 双红  ---- 染黑爸爸,染红爷爷,以爷爷为节点左旋旋
    //              |--- 4.3.2 rl 双红 --- 先以父亲为节点右旋 变成 rr,再同rr操作

    private void insertFixUp(RBNode node){
        this.root.setColor(BLACK);
        RBNode parent = parentOf(node);
        RBNode gparent = parentOf(parent);
        // 情景4:父节点为红
        if(parent != null && isRed(parent)){
            // 如果父节点是 红色,一定右爷爷节点
            RBNode uncle = null;
            if(parent == gparent.left){ // 父亲是爷爷的左子树
                uncle = gparent.right;
                // 4.1 叔叔为红
                if(uncle != null && isRed(uncle)){
                    setBlack(parent);
                    setBlack(uncle);
                    setRed(gparent);
                    insertFixUp(gparent);
                    return ;
                }

                // 4.2.1
                if(uncle == null || isBlack(uncle)){
                    // 4.2.1 LL情况
                    if(node == parent.left){
                        setBlack(parent);
                        setRed(gparent);
                        rightRotate(gparent);
                        return ;
                    }
                    // 4.2.2 LR情况
                    if(node == parent.right){
                        leftRotate(parent);
                        insertFixUp(parent);
                        return ;
                    }
                }
            }else { // 父亲是爷爷的右子树
                uncle = gparent.left;
                // 4.1 叔叔为红
                if(uncle != null && isRed(uncle)){
                    setBlack(parent);
                    setBlack(uncle);
                    setRed(gparent);
                    insertFixUp(gparent);
                    return ;
                }
                // 4.3
                if(uncle == null || isBlack(uncle)){
                    if(node == parent.right){ // rr
                        setBlack(parent);
                        setRed(gparent);
                        leftRotate(gparent);
                    }
                    if(node == parent.left){ // rl
                        rightRotate(parent);
                        insertFixUp(parent);
                        return ;
                    }
                }
            }

        }
    }
    static class RBNode <K extends Comparable<K>, V> {
        private RBNode parent;
        private RBNode left;
        private RBNode right;
        private boolean color;
        private K key;
        private V value;
        public RBNode(){

        }
        public RBNode(RBNode parent, RBNode left, RBNode right, boolean color, K key, V value) {
            this.parent = parent;
            this.left = left;
            this.right = right;
            this.color = color;
            this.key = key;
            this.value = value;
        }

        public RBNode getParent() {
            return parent;
        }

        public void setParent(RBNode parent) {
            this.parent = parent;
        }

        public RBNode getLeft() {
            return left;
        }

        public void setLeft(RBNode left) {
            this.left = left;
        }

        public RBNode getRight() {
            return right;
        }

        public void setRight(RBNode right) {
            this.right = right;
        }

        public boolean isColor() {
            return color;
        }

        public void setColor(boolean color) {
            this.color = color;
        }

        public K getKey() {
            return key;
        }

        public void setKey(K key) {
            this.key = key;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }
    }

}

删除操作: 一样很复杂,找第一个后继结点。

也可不做删除,做个标记,代表删除?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值