一、概述
通过IDEA看下TreeMap的继承关系,继承抽象父类AbstractMap,实现了NavigableMap接口,SortedMap接口,TreeMap是一种有序的Map,从其实现的接口就能看出来。
那么,首先来看下实现的两类接口:
- SortedMap:实现该接口的类,必须按照一定的排序规则保证key的有序性,可以根据key的compareTo()函数或者在构造器中传入Comparator接口的实现类来排序,集合视图遍历的顺序也应与key的顺序一致。
- NavigableMap:实现该接口的类,需实现一些导航方法
TreeMap类,基于红黑树,一种自平衡的二叉查找树,插入和查找的时间复杂度只用O(log n)。
二叉查找树:
- 任意节点最多含有两个子节点。
- 任意节点的左、右节点都可以看做为一棵二叉查找树。
- 如果任意节点的左子树不为空,那么左子树上的所有节点的值均小于它的根节点的值。
- 如果任意节点的右子树不为空,那么右子树上的所有节点的值均大于它的根节点的值。
- 任意节点的key都是不同的。
但是,二叉查找树,在有序的集合下,就会呈现出只有一个分支的情况,例如递增序列,那么二叉树就只有右分支,为了使得这种情况不发生,引入了自平衡,即在树结构倾斜时,通过旋转操作让树趋于平衡。
红黑树,就是一种自平衡的二叉查找树,根据字面理解,节点只有两种状态,非黑即红,两种着色。TreeMap中的每个Entry节点,就是基于这种节点结构,见源码。
二、源码分析
1.SortedMap接口:
public interface SortedMap<K,V> extends Map<K,V> { /** * 返回比较器去对map的key进行排序,否则使用key的自然排序(key自身的compareTo函数) */ Comparator<? super K> comparator(); /** * 返回一个key从fromKey到toKey的左闭右开的子Map(对子Map的修改,会影响原Map集合) */ SortedMap<K,V> subMap(K fromKey, K toKey); // 返回严格小于toKey的子map(对子Map的修改,会影响原Map集合) SortedMap<K,V> headMap(K toKey); // 返回严格大于fromKey的子map(对子Map的修改,会影响原Map集合) SortedMap<K,V> tailMap(K fromKey); // 返回当前集合第一个key K firstKey(); // 返回当前map最后一个key K lastKey(); // 三类集合视图 Set<K> keySet(); Collection<V> values(); Set<Map.Entry<K, V>> entrySet(); }
2.NavigableMap接口:
public interface NavigableMap<K,V> extends SortedMap<K,V> {
// 返回比指定key小的,最大的key对应的键值对,如果找不到则返回null
Map.Entry<K,V> lowerEntry(K key);// 返回比指定key小的,最大的key,如果找不到则返回null
K lowerKey(K key);// 返回比指定key小于等于的,最大的key对应的键值对,如果找不到则返回null
Map.Entry<K,V> floorEntry(K key);// 返回比指定key小于等于的,最大的key,如果找不到则返回null
K floorKey(K key);// 返回比指定key大于等于的,最小的key对应的键值对,如果找不到则返回null
Map.Entry<K,V> ceilingEntry(K key);// 返回比指定key大于等于的,最小的key,如果找不到则返回null
K ceilingKey(K key);// 返回比指定key大于的,最小的key对应的键值对,如果找不到则返回null
Map.Entry<K,V> higherEntry(K key);// 返回比指定key大于的,最小的key,如果找不到则返回null
K higherKey(K key);// 返回第一个的键值对
Map.Entry<K,V> firstEntry();// 返回最后一个键值对
Map.Entry<K,V> lastEntry();// 移除并返回第一个键值对
Map.Entry<K,V> pollFirstEntry();// 移除并返回最后一个键值对
Map.Entry<K,V> pollLastEntry();// 返回当前顺序相反的集合视图
NavigableMap<K,V> descendingMap();// 返回当前map中所有key的集合视图
NavigableSet<K> navigableKeySet();// 返回当前map中所有key的反序的集合视图
NavigableSet<K> descendingKeySet();// 类似于SortedMap里的subMap截取子map,区别是这里指定区间包含属性,是开还是闭
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive);// 截取tokey之前的map,控制是否包含指定的toKey
NavigableMap<K,V> headMap(K toKey, boolean inclusive);// 截取fromKey之后的map,控制是否包含指定的fromKey
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);// 与SortedMap截取一致,左闭右开
SortedMap<K,V> subMap(K fromKey, K toKey);// 截取子map,不包含指定toKey
SortedMap<K,V> headMap(K toKey);// 截取子map,不包含指定fromKey
SortedMap<K,V> tailMap(K fromKey);
}
3.TreeMap类:
Map类通用的方法不在源码里重复。
3.1.构造函数
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
// 比较器
private final Comparator<? super K> comparator;// Root节点(根节点)
private transient Entry<K,V> root;
// 节点个数
private transient int size = 0;// 树内节点修改次数
private transient int modCount = 0;// 默认构造函数,默认使用Key的排序规则进行排序
public TreeMap() {
comparator = null;
}// 提供比较器的构造函数
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}// 提供指定Map集合的构造函数,即使用指定Map的key比较器,对指定Map进行排序
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
}// 提供指定SortedMap集合的构造函数,
public TreeMap(SortedMap<K, ? extends V> m) {
comparator = m.comparator();
try {// ?
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}
3.2.内部类
private static final boolean RED = false; private static final boolean BLACK = true; /** * TreeMap节点 */ 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; /** * 创建新的节点,指定key、value、父节点以及color为黑 */ 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; } public String toString() { return key + "=" + value; } }
3.3.内部方法(default包内可见)
// 根据指定的key,查找对应的键值对 final Entry<K,V> getEntry(Object key) { // 如果比较器不为空,使用比较器 if (comparator != null) return getEntryUsingComparator(key); if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; Entry<K,V> 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; }
/** * 用于getEntry的有比较器的获取entry,用的很少 从根节点出发,往左、往右节点查找 */ final Entry<K,V> getEntryUsingComparator(Object key) { @SuppressWarnings("unchecked") K k = (K) key; Comparator<? super K> cpr = comparator; if (cpr != null) { Entry<K,V> p = root; while (p != null) { int cmp = cpr.compare(k, p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } } return null; }
// 找第一个节点,实际上,找到最左端的节点
final Entry<K,V> getFirstEntry() { Entry<K,V> p = root; if (p != null) while (p.left != null) p = p.left; return p; }
// 找到最后一个节点,实际上,找到最右端的节点
final Entry<K,V> getLastEntry() { Entry<K,V> p = root; if (p != null) while (p.right != null) p = p.right; return p; }
// 返回指定key最近的一个元素,先返回右边的
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) { if (t == null) return null; else if (t.right != null) { Entry<K,V> p = t.right; while (p.left != null) p = p.left; return p; } else { Entry<K,V> p = t.parent; Entry<K,V> ch = t; while (p != null && ch == p.right) { ch = p; p = p.parent; } return p; } }
// 返回指定Entry的key
static <K> K key(Entry<K,?> e) { if (e==null) throw new NoSuchElementException(); return e.key; }
/** * 删除指定节点,并进行修改,以维持平衡 */ private void deleteEntry(Entry<K,V> p) { modCount++; size--; // If strictly internal, copy successor's element to p and then make p // point to successor. if (p.left != null && p.right != null) { Entry<K,V> s = successor(p); p.key = s.key; p.value = s.value; p = s; } // p has 2 children // Start fixup at replacement node, if it exists. Entry<K,V> 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); } else if (p.parent == null) { // return if we are the only node. root = null; } 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; } } }
3.4.查询操作
// 是否包含指定的value,遍历顺序和key一致 public boolean containsValue(Object value) { for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e)) if (valEquals(value, e.value)) return true; return false; }
public K firstKey() { // 返回第一个key return key(getFirstEntry()); }
public K lastKey() { // 返回最后一个key return key(getLastEntry()); }
// NavigableMap的具体实现方法,具体功能见上接口说明
// TreeMap实现使用二叉树的遍历逻辑查找
final Entry<K,V> getCeilingEntry(K key) { Entry<K,V> p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp < 0) { if (p.left != null) p = p.left; else return p; } else if (cmp > 0) { if (p.right != null) { p = p.right; } else { Entry<K,V> parent = p.parent; Entry<K,V> ch = p; while (parent != null && ch == parent.right) { ch = parent; parent = parent.parent; } return parent; } } else return p; } return null; } // 小于指定key最大的key final Entry<K,V> getFloorEntry(K key) { Entry<K,V> p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp > 0) { if (p.right != null) p = p.right; else return p; } else if (cmp < 0) { if (p.left != null) { p = p.left; } else { Entry<K,V> parent = p.parent; Entry<K,V> ch = p; while (parent != null && ch == parent.left) { ch = parent; parent = parent.parent; } return parent; } } else return p; } return null; } // 大于指定key的最小key final Entry<K,V> getHigherEntry(K key) { Entry<K,V> p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp < 0) { if (p.left != null) p = p.left; else return p; } else { if (p.right != null) { p = p.right; } else { Entry<K,V> parent = p.parent; Entry<K,V> ch = p; while (parent != null && ch == parent.right) { ch = parent; parent = parent.parent; } return parent; } } } return null; } // 小于指定key的最大key final Entry<K,V> getLowerEntry(K key) { Entry<K,V> p = root; while (p != null) { int cmp = compare(key, p.key); if (cmp > 0) { if (p.right != null) p = p.right; else return p; } else { if (p.left != null) { p = p.left; } else { Entry<K,V> parent = p.parent; Entry<K,V> ch = p; while (parent != null && ch == parent.left) { ch = parent; parent = parent.parent; } return parent; } } } return null; }
3.5.新增操作
// 新增指定Map到TreeMap中,如果是SortedMap,使用特殊的方法,否则使用通用方法
public void putAll(Map<? extends K, ? extends V> map) { int mapSize = map.size(); if (size==0 && mapSize!=0 && map instanceof SortedMap) { Comparator<?> c = ((SortedMap<?,?>)map).comparator(); if (c == comparator || (c != null && c.equals(comparator))) { ++modCount; try { buildFromSorted(mapSize, map.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } return; } } super.putAll(map); }
public V put(K key, V value) { Entry<K,V> t = root; if (t == null) { // 类型核查,比较器不为空,使用比较器,否则key实现Comparable接口 compare(key, key); // type (and possibly null) check // 指定当前节点为根节点 root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; // split comparator and comparable paths Comparator<? super K> cpr = comparator; if (cpr != null) { // 比较器不为空 do { // 直到型循环 parent = t; // parent 指向最后一个节点 cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } 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<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; }
3.6.删除操作
public V remove(Object key) { Entry<K,V> p = getEntry(key); if (p == null) return null; V oldValue = p.value; deleteEntry(p); return oldValue; }
PS:
- NavigableMap接口的具体实现方法,并没有具体的写。
- TreeMap实际上就是一个树结构,从根节点触发,查找。通过put方法源码,发现除了Root根节点新增时是color=BLACK以外,每个新节点新增时都是RED,下一个节点新增时,fixAfterInsertion函数平衡二叉树后,父节点修改位BLACK。平衡二叉树,使用旋转方法,非平衡状态分为四种:左左、左右、右右、右左,具体的旋转方法理论,这里就不再描述了。