TreeMap原理剖析

简介:

TreeMap是基于红黑树(一种自平衡的二叉查找树)实现的一个有序性的Map。注意该类并不是线程安全的,可以使用Collections.synchronizedSortedMap方法包装TreeMap使之转化成线程安全的map。要了解TreeMap必须先了红黑树原理。

TreeMap类图结构:
TreeMap原理剖析_第1张图片

红黑树的介绍

红黑树(Red-Black Tree,简称R-B Tree),是一种特殊的平衡二叉树。其特点如下:
(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色,每个叶子节点(NIL节点,空节点)是黑色。
(3) 如果一个节点是红色的,则它的子节点必须是黑色的。
(4) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

其示例如下:
TreeMap原理剖析_第2张图片
在TreeMap添加删除元素的过程中保持红黑树的特性,则必须通过以下三种功能来保证:着色,左旋,右旋。

TreeMap主要方法如下:

1 put(K key, V value)方法:

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);
            //TreeMap的节点数+1
            size = 1;
             //TreeMap修改次数+1
            modCount++;
            return null;
        }
        // 使用cmp来表示排序比较结果
        int cmp;
        //父节点
        Entry parent;
        // split comparator and comparable paths
        Comparator cpr = comparator;
        // 比较器不为空
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                // cmp < 0,表示新增节点的key小于当前节点的key,则以当前节点的左子节点作为新的当前节点
                if (cmp < 0)
                    t = t.left;
                 // cmp < 0,表示新增节点的key大于当前节点的key,则以当前节点的右子节点作为新的当前节点
                else if (cmp > 0)
                    t = t.right;
                else
                    // 比较结果等于0,说明key相等,覆盖旧值
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            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);
        }
        // 创建新节点e
        Entry e = new Entry<>(key, value, parent);
        if (cmp < 0)
           // 将e放到当前节点的左边,作为左子树
            parent.left = e;
        else
         // 将e放到当前节点的右边,作为右子树
            parent.right = e;
        // 插入完成,对二叉树进行平衡操作:通过左旋(rotateLeft())、右旋(rotateRight())和着色(setColor)生成一个新的红黑树。
        fixAfterInsertion(e);
         //TreeMap的节点数+1
        size++;
         //TreeMap的修改次数+1
        modCount++;
        return null;
    }

2 get(Object key)方法:

public V get(Object key) {
    Entry p = getEntry(key);
    return (p==null ? null : p.value);
}
final Entry getEntry(Object key) {
    // 使用Comparator进行比较
    if (comparator != null)
        return getEntryUsingComparator(key);
    if (key == null)
        throw new NullPointerException();
    @SuppressWarnings("unchecked")
        Comparable k = (Comparable) key;
    Entry p = root;
    // 从根节点开始,不断比较key的大小进行查找
    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;
    }
    // 没有相等的key,返回null
    return null; 
}

你可能感兴趣的:(JDK源码)