美文网首页
红黑树的插入

红黑树的插入

作者: YAOPRINCESS | 来源:发表于2020-08-30 16:58 被阅读0次
/**
 * @author klr
 * @create 2020-08-29-21:58
 */
public class RedBlackTree<K extends Comparable<K>, V> {
    //定义红黑色
    private static final boolean RED = false;
    private static final boolean BLACK = true;

    //定义根节点
    private RBNode root;

    public RBNode getRoot() {
        return root;
    }

    /**
     * 围绕p点左旋
     *              pf                  pf
     *            /                   /
     *          p                   pr(r)
     *        /  \                 /  \
     *      pl    pr(r)           p     rr
     *          /   \           /  \
     *         rl   rr         pl   rl
     *
     * @param p
     */
    public void leftRotate(RBNode p) {
        if (p != null) {
            RBNode r = p.right;//先记录r的信息

            p.right = r.left;//r.left为不为null无所谓
            if (r.left != null) {
                r.left.parent = p;//rl的父节点指向p了
            }

            r.parent = p.parent;
            if (p.parent == null) {
                //此时表明p为根节点,旋转后,r称为根节点}
                root = r;
            } else if (p.parent.left == p) {
                //说明p为pf的左节点
                p.parent.left = r;//把pf指向r
            } else {
                p.parent.right = r;
            }
            r.left = p;
            p.parent = r;
        }
    }

    /**
     * 右旋为左旋的镜像
     * @param p
     */
    public void rightRotate(RBNode p) {
        if (p != null) {
            RBNode l = p.left;//先记录r的信息

            p.left = l.right;//r.left为不为null无所谓
            if (l.right != null) {
                l.right.parent = p;//rl的父节点指向p了
            }

            l.parent = p.parent;
            if (p.parent == null) {
                //此时表明p为根节点,旋转后,r称为根节点}
                root = l;
            } else if (p.parent.right == p) {
                //说明p为pf的左节点
                p.parent.right = l;//把pf指向r
            } else {
                p.parent.left = l;
            }
            l.right = p;
            p.parent = l;
        }
    }


    //新增结点
    public void put(K key, V value) {

        if (key == null) {
            throw new NullPointerException();
        }

        RBNode t = this.root;
        //先判断是否有根节点
        if (t == null) {
            this.root = new RBNode<>(key, (value == null ? key : value), null);
            return;
        }

        //寻找插入位置,定义双亲指针
        RBNode parent;
        int cmp;
        //已有根节点后
        do {
            parent=t;
            cmp = key.compareTo((K) t.getKey());
            if (cmp < 0) {
                //key小于结点的key说明往左边走
                t = t.getLeft();
            } else if (cmp > 0) {
                t = t.getRight();
            } else {
                //key相等时替换原来的value值
                t.setValue(value == null ? key : value);
                return;
            }
        } while (t != null);

        //此时parent为要插入的key结点的父节点,t为空
        RBNode<K, Object> e = new RBNode<>(key, (value == null ? key : value), parent);
        //别忘了让父节点指向插入的新节点
        if (cmp < 0) {
            parent.setLeft(e);
        } else {
            parent.setRight(e);
        }

        //插入完决定是否旋转
        fixAfterPut(e);

    }

    public boolean color(RBNode node) {
        return node == null ? BLACK : node.color;
    }

    public RBNode parentOf(RBNode node) {
        return node != null ? node.parent : null;
    }

    public RBNode leftOf(RBNode node) {
        return node != null ? node.left : null;
    }

    public RBNode rightOf(RBNode node) {
        return node != null ? node.right : null;
    }

    //只有    新增元素+3结点    需要旋转(4种行态),除了2结点其他需要变色
    public void fixAfterPut(RBNode<K, Object> x) {
        //新增结点均为红色
        x.color = RED;
        //只有一个结点(2结点)不用变色和旋转

        //此时x和父节点均为红色,需要根据条件选择是否旋转或变色
        RBNode y;
        while (x != null && x != root && x.getParent().color == RED) {
            //x的父节点为爷爷结点的左节点,里面又分为2种情况
            //左3
            if (parentOf(x)==leftOf(parentOf(parentOf(x)))) {
                //叔叔结点
                y=rightOf(parentOf(parentOf(x)));
                //如果有叔叔结点,说明4节点裂变
                if (color(y) == RED) {
                    //爷爷节点变成红色
                    parentOf(y).color = RED;
                    //父节点和叔叔节点变成黑色
                    parentOf(x).color = BLACK;
                    y.color = BLACK;
                    //此时需要递归,防止爷爷节点与它上面的节点都为红色
                    x = parentOf(parentOf(x));
                }else {
                    //x为父节点的右结点形态时,先左旋一下
                    if (x == rightOf(parentOf(x))) {
                        x = parentOf(x);
                        leftRotate(x);
                    }
                    //调整为整体左3的情况
                    //先变色
                    parentOf(x).color = BLACK;
                    parentOf(parentOf(x)).color = RED;
                    rightRotate(parentOf(parentOf(x)));
                }
            }
            //x的父节点为爷爷结点的右节点
            else {

                //叔叔结点
                y=leftOf(parentOf(parentOf(x)));
                //如果有叔叔结点,说明4节点裂变
                if (color(y) == RED) {
                    //爷爷节点变成红色
                    parentOf(y).color = RED;
                    //父节点和叔叔节点变成黑色
                    parentOf(x).color = BLACK;
                    y.color = BLACK;
                    //此时需要递归,防止爷爷节点与它上面的节点都为红色
                    x = parentOf(parentOf(x));
                }else {
                    //x为父节点的右结点形态时,先左旋一下
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rightRotate(x);
                    }
                    //调整为整体左3的情况
                    //先变色
                    parentOf(x).color = BLACK;
                    parentOf(parentOf(x)).color = RED;
                    leftRotate(parentOf(parentOf(x)));
                }
            }

        }
        root.color = BLACK;
    }


    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(K key, V value, RBNode parent) {
            this.parent = parent;
            this.key = key;
            this.value = value;

            //设置默认颜色为黑色
            this.color = BLACK;
        }

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

        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;
        }
    }

}

相关文章

  • 数据结构—树—红黑树

    红黑树概述 红黑树的插入 红黑树的删除

  • 彻底理解红黑树(二)之 插入

    彻底理解红黑树(一)之 二叉搜索树彻底理解红黑树(二)之 插入彻底理解红黑树(三)之 删除 前言 红黑树的插入情况...

  • [转载]红黑树

    https://zhuanlan.zhihu.com/p/24367771红黑树简介红黑树插入红黑树删除

  • 彻底理解红黑树(三)之 删除

    彻底理解红黑树(一)之 二叉搜索树彻底理解红黑树(二)之 插入彻底理解红黑树(三)之 删除 前言 红黑树的删除情况...

  • Collection

    图解集合 8 : 红黑树的移除节点操作 图解集合7:红黑树概念、红黑树的插入及旋转操作详细解读 图解集合 6 : ...

  • 红黑树核心之节点新增

    红黑树插入算法 红黑树节点插入与二叉搜索树类似,由根节点开始寻找待插入的位置。与二叉搜索树不同的内容大致有如下几点...

  • 红黑树的插入

  • 红黑树专题

    0.目录 1.算法导论的红黑树本质上是2-3-4树 2.红黑树的结构和性质 3.红黑树的插入 4.红黑树的删除 5...

  • 彻底理解红黑树(一)之二叉搜索树

    彻底理解红黑树(一)之二叉搜索树彻底理解红黑树(二)之插入彻底理解红黑树(三)之删除 1. 二叉搜索树的定义 二叉...

  • 从二叉树到红黑树

    一说到红黑树,有人就特别恐惧,立马想到的是红黑树的性质啊,插入方式啊,复杂的旋转啊。网上一搜索红黑树,也是这些...

网友评论

      本文标题:红黑树的插入

      本文链接:https://www.haomeiwen.com/subject/zzeesktx.html