TreeMap的源码学习

内容来自-码出高效

public class RedBlackSourceCode {

    public V put(K key, V value) {
        // t表示当前节点,记住这个很重要。先把TreeMap的根节点root引用赋值给当前节点
        TreeMap.Entry<K,V> t = root;
        // 如果当前节点为null,即是空树,新增的KV形式的节点就是根节点
        if (t == null) {
            // 看似多此一举,实际上预检了key是否可以比较
            compare(key, key); // type (and possibly null) check
            // 使用KV构造出新的Entry对象,其中第三个参数就是parent,根节点没有父节点
            root = new TreeMap.Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        // 接收比较结果
        int cmp;
        TreeMap.Entry<K,V> parent;
        // 构造方法中置入的外部比较器
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        // todo 重点步骤,根据二叉查找树的特性,找到新节点插入的合适位置
        if (cpr != null) {
            // 循环的目标,根据参数key与当前节点的key不断的进行比较
            do {
                // 当前节点赋值给父节点,故从根节点开始遍历比较
                parent = t;
                // 比较输入的参数key和当前节点key的大小
                cmp = cpr.compare(key, t.key);
                // 参数的key更小,向左边走,把当前节点引用移动到它的左子节点上
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                // 如果相等,覆盖当前节点的值,返回更新前的值。
                else
                    return t.setValue(value);
                // 如果没有相等的key,一直会遍历到NIL节点为止
            } while (t != null);
        }
        // 在没有指定比较器的情况下,调用自然排序的Comparable比较
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        // 创建Entry对象,并把parent置入参数
        TreeMap.Entry<K,V> e = new TreeMap.Entry<>(key, value, parent);
        // 新节点找到自己的位置,原本以为就可以安顿下来---------
        if (cmp < 0)
            // 如果比较结果小于0,则成为parent的左孩子
            parent.left = e;
        else
            parent.right = e;
        // 还需要对这个新节点进行重新着色和旋转操作,以达到平衡
        fixAfterInsertion(e);
        size++;
        modCount++;
        // 成功插入新节点后,返回null
        return null;
    }
    /** From CLR */
    private void fixAfterInsertion(TreeMap.Entry<K,V> x) {
        // 虽然内部类Entry的属性color默认为黑色,但是新节点一律先赋值为红色
        x.color = RED;

        /*新节点是根节点或者其父节点(简称父亲)为黑色
        *插入红色节点并不会破坏红黑树的性质,无须调整
        * x值改变的过程是在不断地向上游遍历,直到父亲为黑色,或者到达根节点
        * */
        while (x != null && x != root && x.parent.color == RED) {
            // 如果父亲是其父节点(爷爷)的左子节点
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                // 这时,得到爷爷的右子节点(右叔)的脸色
                TreeMap.Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                // 如果右叔是红色的,此时通过局部颜色调整,就可以使子树继续满足红黑树性质
                // todo 第一处
                if (colorOf(y) == RED) {
                    // 父亲设置为黑色
                    setColor(parentOf(x), BLACK);
                    // 右叔设置为黑色
                    setColor(y, BLACK);
                    // 爷爷设置为红色
                    setColor(parentOf(parentOf(x)), RED);
                    // 爷爷成为新的节点,进入到下一轮循环
                    x = parentOf(parentOf(x));
                    // 如果右叔是黑色,则需要加入旋转
                } else {
                    // 对父亲做一次左旋转操作,红色的父亲会沉入其左侧位置
                    // 将父亲赋值给x
                    if (x == rightOf(parentOf(x))) {
                        // 对父亲做一次左旋转操作,红色的父亲会沉入其左侧位置
                        // 将父亲赋值给x
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    // 重新着色并对爷爷进行右旋转操作
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {
                TreeMap.Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }

    // 左旋转
    private void rotateLeft(TreeMap.Entry<K,V> p) {
        // 如果参数节点不是NIL节点
        if (p != null) {
            // 获取p的右子节点r
            TreeMap.Entry<K,V> r = p.right;
            // 将 r的左子树 赋值给 p的右子树
            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;
            // 将p设置为r的左子树,将r设置为p的父亲
            r.left = p;
            p.parent = r;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值