源码阅读 - TreeMap

0. TreeMap是什么

  • 基于红黑树的NavigableMap实现,排序的依据是创建时指定的Comparator(如果有指定)或者Key的自然顺序(如果key实现了Comparable)。
  • 保证了log(n)时间的添加、删除、查询操作。
  • 非同步

1. 实现的本质

红黑树
节点的结构:
包含3个引用:分别指向左子、右子、父节点,以及一个颜色域。

static final class Entry implements Map.Entry {
    K key;
    V value;
    Entry left;
    Entry right;
    Entry parent;
    boolean color = BLACK;
    /**
     * Make a new cell with given key, value, and parent, and with
     * {@code null} child links, and BLACK color.
     */
    //新建节点为黑色
    Entry(K key, V value, Entry parent) {
        this.key = key;
        this.value = value;
        this.parent = parent;
    }
}

2. 常用api解析

2.1 构造函数

//无参
public TreeMap()
//指定comparator
public TreeMap(Comparator comparator)
//参数为Map集合
public TreeMap(Map m)
public TreeMap(SortedMap m)

2.2 put方法

先将节点放入正确位置,此时可能违反红黑树的性质,需要进行调整。

/**
 * Associates the specified value with the specified key in this map.
 * If the map previously contained a mapping for the key, the old
 * value is replaced.
 *
 * @param key key with which the specified value is to be associated
 * @param value value to be associated with the specified key
 *
 * @return the previous value associated with {@code key}, or
 *         {@code null} if there was no mapping for {@code key}.
 *         (A {@code null} return can also indicate that the map
 *         previously associated {@code null} with {@code key}.)
 * @throws ClassCastException if the specified key cannot be compared
 *         with the keys currently in the map
 * @throws NullPointerException if the specified key is null
 *         and this map uses natural ordering, or its comparator
 *         does not permit null keys
 */
public V put(K key, V value) {
    Entry t = root;
    //建立根节点
    if (t == null) {
        compare(key, key); // type (and possibly null) check
        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry parent;
    // split comparator and comparable paths
    Comparator cpr = comparator;
    //如果指定了comparator,则使用comparator比较
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            //小的左转,大的右转
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                //找到相当的key时
                return t.setValue(value);
        } while (t != null);
        //循环完成时,t指向要插入的位置,parent指向父节点
    }
    //未指定comparator时
    else {
        //key不能为null
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable k = (Comparable) 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);
    }
    //此时t指向要插入的位置,parent指向父节点
    Entry e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    //调整
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}

/** From CLR */
//x是新插入的节点
private void fixAfterInsertion(Entry x) {
    x.color = RED;
    //当x的父节点是红色时
    while (x != null && x != root && x.parent.color == RED) {
        //x的父节点是祖父节点的左孩子
        if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
            //y是x的叔叔节点
            Entry y = rightOf(parentOf(parentOf(x)));
            //如果叔叔节点是红色
            if (colorOf(y) == RED) {
                //父节点和叔叔节点变黑,祖父节点变红
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                setColor(parentOf(parentOf(x)), RED);
                //x指向祖父节点继续循环
                x = parentOf(parentOf(x));
            //如果叔叔节点是黑色
            } else {
                //如果x是父节点的右孩子
                if (x == rightOf(parentOf(x))) {
                    //先将父节点左旋
                    x = parentOf(x);
                    rotateLeft(x);
                }
                //左旋之后,x变为左孩子
                //x的父节点变黑,祖父节点变红,然后祖父节点右旋
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateRight(parentOf(parentOf(x)));
            }
        //x的父节点是祖父节点的右孩子,与上面的过程互为镜像
        } else {
            //y是x的叔叔节点
            Entry y = leftOf(parentOf(parentOf(x)));
            //如果叔叔节点是红色
            if (colorOf(y) == RED) {
                //父节点和叔叔节点变黑,祖父节点变红
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                setColor(parentOf(parentOf(x)), RED);
                //x指向祖父节点,继续循环
                x = parentOf(parentOf(x));
            //如果叔叔节点是黑色
            } else {
                //如果x是父节点的左孩子
                if (x == leftOf(parentOf(x))) {
                    //x指向父节点,然后右旋,右旋后x变为右孩子
                    x = parentOf(x);
                    rotateRight(x);
                }
                //父节点变黑,祖父节点变红,祖父节点左旋
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateLeft(parentOf(parentOf(x)));
            }
        }
    }
    //根节点变黑
    root.color = BLACK;
}

2.3 get方法

根据key查找value的方法和普通的BST查找节点的方法一样。

/**
 * Returns the value to which the specified key is mapped,
 * or {@code null} if this map contains no mapping for the key.
 *
 * 

More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code key} compares * equal to {@code k} according to the map's ordering, then this * method returns {@code v}; otherwise it returns {@code null}. * (There can be at most one such mapping.) * *

A return value of {@code null} does not necessarily * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. * * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key is null * and this map uses natural ordering, or its comparator * does not permit null keys */ public V get(Object key) { Entry p = getEntry(key); return (p==null ? null : p.value); } /** * Returns this map's entry for the given key, or {@code null} if the map * does not contain an entry for the key. * * @return this map's entry for the given key, or {@code null} if the map * does not contain an entry for the key * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key is null * and this map uses natural ordering, or its comparator * does not permit null keys */ final Entry getEntry(Object key) { // Offload comparator-based version for sake of performance if (comparator != null) return getEntryUsingComparator(key); if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable k = (Comparable) key; Entry p = root; while (p != null) { int cmp = k.compareTo(p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } return null; }

2.4 remove方法

/**
 * Removes the mapping for this key from this TreeMap if present.
 *
 * @param  key key for which mapping should be removed
 * @return the previous value associated with {@code key}, or
 *         {@code null} if there was no mapping for {@code key}.
 *         (A {@code null} return can also indicate that the map
 *         previously associated {@code null} with {@code key}.)
 * @throws ClassCastException if the specified key cannot be compared
 *         with the keys currently in the map
 * @throws NullPointerException if the specified key is null
 *         and this map uses natural ordering, or its comparator
 *         does not permit null keys
 */
public V remove(Object key) {
    //找到正确的节点
    Entry p = getEntry(key);
    if (p == null)
        return null;
    V oldValue = p.value;
    //删除节点p
    deleteEntry(p);
    return oldValue;
}

/**
 * Delete node p, and then rebalance the tree.
 */
private void deleteEntry(Entry p) {
    modCount++;
    size--;
    // If strictly internal, copy successor's element to p and then make p
    // point to successor.
    //如果p的左右孩子都不为空
    if (p.left != null && p.right != null) {
        //s指向p的后继节点
        Entry s = successor(p);
        //后继节点的值放到当前节点
        p.key = s.key;
        p.value = s.value;
        //然后将p指向后继节点
        p = s;
    } // p has 2 children
    // Start fixup at replacement node, if it exists.
    //此时p是真正要删除的节点,并且p只有左子或右子或都为空
    Entry replacement = (p.left != null ? p.left : p.right);
    //只有左子或右子时,左子或右子取代当前节点
    if (replacement != null) {
        // Link replacement to parent
        replacement.parent = p.parent;
        if (p.parent == null)
            root = replacement;
        else if (p == p.parent.left)
            p.parent.left  = replacement;
        else
            p.parent.right = replacement;
        // Null out links so they are OK to use by fixAfterDeletion.
        p.left = p.right = p.parent = null;
        // Fix replacement
        //如果删除的是红节点,不影响红黑树的性质,如果是黑节点,则需要进行调整
        if (p.color == BLACK)
            fixAfterDeletion(replacement);
    //如果p是根节点
    } else if (p.parent == null) { // return if we are the only node.
        root = null;
    //如果p没有子节点
    } else { //  No children. Use self as phantom replacement and unlink.
        if (p.color == BLACK)
            fixAfterDeletion(p);
        if (p.parent != null) {
            if (p == p.parent.left)
                p.parent.left = null;
            else if (p == p.parent.right)
                p.parent.right = null;
            p.parent = null;
        }
    }
}

/**
 * Returns the successor of the specified Entry, or null if no such.
 */
//查找节点t的后继节点
static  TreeMap.Entry successor(Entry t) {
    if (t == null)
        return null;
    //如果t的右子不为空,右子向左走到底
    else if (t.right != null) {
        Entry p = t.right;
        while (p.left != null)
            p = p.left;
        return p;
    //如果t的右子为空,向上走,到某一个节点是其父节点的左子,该父节点为t的后继
    } else {
        Entry p = t.parent;
        Entry ch = t;
        while (p != null && ch == p.right) {
            ch = p;
            p = p.parent;
        }
        return p;
    }
}

/** From CLR */
private void fixAfterDeletion(Entry x) {
    //如果x是黑色,则进行操作
    // x节点可能是被删除节点的子节点(可能为红色),或者其本身(如果它没有子节点)
    while (x != root && colorOf(x) == BLACK) {
        //如果x是左孩子
        if (x == leftOf(parentOf(x))) {
            //sib是x的兄弟节点
            Entry sib = rightOf(parentOf(x));
            //如果兄弟节点是红色
            if (colorOf(sib) == RED) {
                //交换兄弟节点和父节点的颜色,父节点左旋
                setColor(sib, BLACK);
                setColor(parentOf(x), RED);
                rotateLeft(parentOf(x));
                //sib指向新的兄弟节点(必定是黑色)
                sib = rightOf(parentOf(x));
            }
            //如果sib的两个孩子都是黑色
            if (colorOf(leftOf(sib))  == BLACK &&
                colorOf(rightOf(sib)) == BLACK) {
                //sib设为红色,x指向父节点,继续循环
                setColor(sib, RED);
                x = parentOf(x);
            } else {
                //如果兄弟节点是左红右黑
                if (colorOf(rightOf(sib)) == BLACK) {
                    //兄弟节点和左孩子颜色互换,然后右旋
                    setColor(leftOf(sib), BLACK);
                    setColor(sib, RED);
                    rotateRight(sib);
                    //sib指向新的兄弟节点
                    sib = rightOf(parentOf(x));
                }
                //此时兄弟节点是左黑右红
                //则交换x的父节点和兄弟节点颜色,兄弟右节点设为黑色,父节点左旋
                setColor(sib, colorOf(parentOf(x)));
                setColor(parentOf(x), BLACK);
                setColor(rightOf(sib), BLACK);
                rotateLeft(parentOf(x));
                //结束循环
                x = root;
            }
        //如果x是右孩子,与if分支对称
        } else { // symmetric
            //sib是x的兄弟节点
            Entry sib = leftOf(parentOf(x));
            //如果兄弟节点是红色
            if (colorOf(sib) == RED) {
                //交换兄弟节点和父节点颜色,父节点右旋
                setColor(sib, BLACK);
                setColor(parentOf(x), RED);
                rotateRight(parentOf(x));
                //sib指向新的兄弟节点
                sib = leftOf(parentOf(x));
            }
            //此时sib必定为黑色
            //如果sib左右孩子均为黑色
            if (colorOf(rightOf(sib)) == BLACK &&
                colorOf(leftOf(sib)) == BLACK) {
                //将sib设为红色,x指向父节点,继续循环
                setColor(sib, RED);
                x = parentOf(x);
            } else {
                //如果兄弟节点的孩子左黑右红
                if (colorOf(leftOf(sib)) == BLACK) {
                    //交换兄弟节点和右孩子颜色,兄弟节点左旋
                    setColor(rightOf(sib), BLACK);
                    setColor(sib, RED);
                    rotateLeft(sib);
                    //sib指向新的兄弟节点
                    sib = leftOf(parentOf(x));
                }
                //此时兄弟节点孩子必定左红右黑
                //互换兄弟节点和父节点颜色,兄弟节点左孩子设为黑色,父节点右旋
                setColor(sib, colorOf(parentOf(x)));
                setColor(parentOf(x), BLACK);
                setColor(leftOf(sib), BLACK);
                rotateRight(parentOf(x));
                //结束循环
                x = root;
            }
        }
    }
    //如果x是红色,则将x设为黑色即可
    setColor(x, BLACK);
}

3. 参考

  1. TreeMap源码build 1.8.0_121-b13版本
  2. 二叉树 - 红黑树

你可能感兴趣的:(源码阅读 - TreeMap)