基于jdk1.8 TreeMap详解红黑树插入原理

package arraylist;

import java.util.Map;

/**
 * @author mawt
 * @description
 * @date 2020/7/28
 */
public class TreeMap<K, V> {
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    private transient Entry<K, V> root;

    static final class Entry<K, V> implements Map.Entry<K, V> {
        K key;
        V value;
        Entry<K, V> left;
        Entry<K, V> right;
        Entry<K, V> parent;
        boolean color = BLACK;

        Entry(K key, V value, Entry<K, V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

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

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;

            return valEquals(key, e.getKey()) && valEquals(value, e.getValue());
        }

        public int hashCode() {
            int keyHash = (key == null ? 0 : key.hashCode());
            int valueHash = (value == null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        }
    }

    /**
     * 红黑树定义和性质
     * 红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须满足下面性质:
     * <p>
     * 性质1:每个节点要么是黑色,要么是红色。
     * 性质2:根节点是黑色。
     * 性质3:每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
     * 性质4:如果一个节点是红色的,则它的子节点必须是黑色的。
     * 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
     * <p>
     * 从性质5又可以推出:
     * 性质5.1:如果一个结点A存在黑子结点,那么该结点A肯定有两个子结点
     * <p>
     * 节点情况汇总:
     * 1.新增节点颜色:红、黑
     * 2.新增节点位置:左、右
     * 3.父节点颜色:红、黑
     * 4.父节点位置:左、右
     * 5.叔叔节点:不存在、存在且为红色、存在且为黑色
     * 总计有 2 * 2 * 2 * 2 * 3 = 48种情况需要讨论
     * <p>
     * 前提:
     * 1.插入节点x前,该树一定满足红黑树的所有特性;
     * 2.插入节点x后经过旋转或变色,该树一定满足红黑树的所有特性
     *
     * I.情况1:新增节点颜色一定为红(如果为黑就破坏了红黑树平衡5此时就需要额外操作来平衡红黑树了)
     * 此时就只有2 * 2 * 2 * 3 = 24种情况需要讨论了
     *
     * II.情况3:如果父节点为黑色,此时新增节点为红,并没有破坏红黑树平衡,自平衡就此结束了,所有我们只需要讨论父节点为红色的情况就可以了
     * 此时就只有2 * 2 * 3 = 12种情况需要讨论了
     * 需要讨论的有:  2.新增节点位置:左、右
     *              4.父节点位置:左、右
     *              5.叔叔节点:不存在、存在且为红色、存在且为黑色
     *
     * III.经过II的分析,此时父节点为红色,祖父节点一定存在并且是黑色(红黑树特性4)
     * 先讨论5:假设叔叔节点r存在并且为黑色,情况就会是这样:
     *      黑pp       黑pp
     *   红p  黑r   黑r  红p
     * 因为在新插入节点前,该树一定要满足红黑树所有特性,但是这2种情况并不满足,所有这2种情况并不存在,就不需要讨论了
     * 此时就只有2 * 2 * 2 = 8种情况需要讨论了
     * 需要讨论的有:  2.新增节点位置:左、右
     *              4.父节点位置:左、右
     *              5.叔叔节点:不存在、存在且为红色
     *
     * IV.
     * 树1:     黑pp
     *       红p
     *    红x
     *
     * 树2:      黑pp
     *       红p
     *          红x
     *
     * 树3:     黑pp
     *              红p
     *                  红x
     *
     * 树4:     黑pp
     *              红p
     *            红x
     *
     * 树5:     黑pp
     *       红p  红r
     *    红x
     *
     * 树6:      黑pp
     *       红p    红r
     *         红x
     *
     * 树7:     黑pp
     *      红r    红p
     *               红x
     *
     * 树8:     黑pp
     *      红r    红p
     *           红x
     *
     *
     * @param x
     */
    private void fixAfterInsertion(Entry<K, V> x) {
        x.color = RED;  //默认新增节点颜色为red
        while (x != null && x != root && x.parent.color == RED) { //父节点为红色,祖父节点一定是黑色
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { //父节点是左子树
                Entry<K, V> y = rightOf(parentOf(parentOf(x))); // 叔叔节点
                if (colorOf(y) == RED) { //叔叔节点存在并且是红色  例5和例6
                    setColor(parentOf(x), BLACK);        //      黑pp           黑pp
                    setColor(y, BLACK);                  //    红p  红y       红p  红y
                    setColor(parentOf(parentOf(x)), RED);//  红x               红x
                    x = parentOf(parentOf(x));
                    //存在连续的2个红节点,违反了红黑树特性,需要平衡
                    //1.如果将红x变黑,那么红p的左子树凭空多了一个黑色节点,违反了红黑树特性5,
                    //  所以我们必须将红p的右子树添加一个黑节点,不好搞,放弃此种变色
                    //2.如果将红p变黑,那么黑pp的左子树凭空多了一个黑色节点,违反了红黑树特性5,
                    //  所以直接将红y变黑,那么从黑pp出发满足红黑树特性5,如果黑pp有父节点ppp,
                    //  那么ppp的左子树到任意叶子结点的路径中多了一个黑色节点,为了满足特性5,
                    //  我们将黑pp变红,满足红黑树特性5,但是此时为什么不退出while循环呢,
                    //  因为我们将黑pp变红后,并不清楚ppp是哪种颜色,有可能不满足红黑树特性4,
                    //  此时有可能是这样:
                    //          红ppp
                    //       红pp
                    //    黑p   黑y
                    // 红x
                    // 所有执行x = parentOf(parentOf(x))将x执行红pp继续while循环,
                    // 如果将x执行黑p或者黑y时,它们作为新插入节点时颜色并不是红色,跟新插入节点颜色为red矛盾
                } else {    //叔叔节点不存在或叔叔节点为黑色
                    if (x == rightOf(parentOf(x))) {    //      黑pp           黑pp
                        //当前节点是右子节点 例2            //    红p            红p  黑y 此种情况不可能发生
                        x = parentOf(x);                //      红x            红x
                        rotateLeft(x);//左旋p
                        //存在连续的2个红节点,违反了红黑树特性,需要平衡
                        //1.如果将红x变黑,那么红p的左子树凭空多了一个黑色节点,违反了红黑树特性5,
                        //  所以我们必须将红p的右子树添加一个黑节点,不好搞,放弃此种变色
                        //2.如果将红p变黑,那么黑pp的左子树凭空多了一个黑色节点,
                        //  黑pp的右子树为null,违反了红黑树特性5,放弃此种变色
                        //3.因为红x在红p的右子树上,需要对红p进行左旋,变成这样了:
                        //      黑pp
                        //   红xx         红xx就是原来的红x
                        // 红x            红x就是原来的红p
                    } else { //例1
                        //当前节点是左子节点               //      黑pp           黑pp
                                                        //    红p            红p  黑y 此种情况不可能发生
                                                        //  红x            红x
                    }
                    //经过ifelse后,变成这样了
                    //      黑pp
                    //   红p
                    // 红x
                    //1.将红p变黑,黑pp变红,右旋黑pp,变成这样了:
                    //    黑p
                    // 红x  红pp
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {//父节点是右子树
                Entry<K, V> y = leftOf(parentOf(parentOf(x)));//叔叔节点
                if (colorOf(y) == RED) { //叔叔节点存在并且是红色  例7和例8
                    setColor(parentOf(x), BLACK);        //      黑pp           黑pp
                    setColor(y, BLACK);                  //    红y  红p       红y  红p
                    setColor(parentOf(parentOf(x)), RED);//       红x               红x
                    x = parentOf(parentOf(x));
                } else {    //叔叔节点不存在或叔叔节点为黑色
                    if (x == leftOf(parentOf(x))) {     //      黑pp           黑pp
                        //当前节点是左子节点 例4            //         红p      黑y    红p 此种情况不可能发生
                        x = parentOf(x);                //       红x             红x
                        rotateRight(x);
                    } else { //例3
                        //当前节点是右子节点               //      黑pp           黑pp
                                                        //         红p       黑y   红p 此种情况不可能发生
                                                        //           红x            红x
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }

    static final boolean valEquals(Object o1, Object o2) {
        return (o1 == null ? o2 == null : o1.equals(o2));
    }

    private static <K, V> boolean colorOf(Entry<K, V> p) {
        return (p == null ? BLACK : p.color);
    }

    private static <K, V> Entry<K, V> parentOf(Entry<K, V> p) {
        return (p == null ? null : p.parent);
    }

    private static <K, V> void setColor(Entry<K, V> p, boolean c) {
        if (p != null)
            p.color = c;
    }

    private static <K, V> Entry<K, V> leftOf(Entry<K, V> p) {
        return (p == null) ? null : p.left;
    }

    private static <K, V> Entry<K, V> rightOf(Entry<K, V> p) {
        return (p == null) ? null : p.right;
    }

    private void rotateLeft(Entry<K, V> p) {
        if (p != null) {
            Entry<K, V> r = p.right;
            p.right = r.left;
            if (r.left != null)
                r.left.parent = p;
            r.parent = p.parent;
            if (p.parent == null)
                root = r;
            else if (p.parent.left == p)
                p.parent.left = r;
            else
                p.parent.right = r;
            r.left = p;
            p.parent = r;
        }
    }

    private void rotateRight(Entry<K, V> p) {
        if (p != null) {
            Entry<K, V> l = p.left;
            p.left = l.right;
            if (l.right != null) l.right.parent = p;
            l.parent = p.parent;
            if (p.parent == null)
                root = l;
            else if (p.parent.right == p)
                p.parent.right = l;
            else p.parent.left = l;
            l.right = p;
            p.parent = l;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33436466/article/details/107655041