原始碼分析三、Map(3)-TreeMap
一、概述
通過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) { 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; 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介面的具體實現方法,並沒有具體的寫。