Java集合类-TreeMap分析
TreeMap的特点
TreeMap基于红黑树实现
红黑树是一种弱平衡的二叉树,比AVL树旋转次数少,用弱平衡换取旋转次数
有5个性质:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点(NIL节点,空节点)是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
特性:最长路径不会长于最短路径2倍
成员变量
private final Comparator<? super K> comparator; // 结点的比较器,用于对树的结点进行排序
树的结点
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; }
构造函数
共有4个构造函数
1、无参构造函数,不指定比较器
public TreeMap() { comparator = null; }
2、无参构造函数,指定比较器
public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; }
3、参数是Map的构造函数
public TreeMap(Map<? extends K, ? extends V> m) { comparator = null; putAll(m); }
下面详细分析下putAll函数
public void putAll(Map<? extends K, ? extends V> map) { int mapSize = map.size(); // 如果TreeMap的size为0,且放入的map的size不是0,且是已排序的Map if (size==0 && mapSize!=0 && map instanceof SortedMap) { Comparator<?> c = ((SortedMap<?,?>)map).comparator(); // 放入map的比较器和TreeMap的比较器相同,使用buildFromSorted构建 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; } } // 遍历插入map中的结点到TreeMap super.putAll(map); }
1、如果TreeMap中没有结点,且插入的map是有已排序的map,并且map的比较器和TreeMap的比较器相同,则使用buildFromSorted进行插入
2、否则遍历map中的结点,然后插入到TreeMap
4、参数是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) { } }
插入的已排序的map,直接使用buildFromSorted进行插入
下面分析下buildFromSorted是如何插入map到TreeMap的
private static int computeRedLevel(int sz) { int level = 0; for (int m = sz - 1; m >= 0; m = m / 2 - 1) level++; return level; }
private final Entry<K,V> buildFromSorted(int level, int lo, int hi, int redLevel, Iterator<?> it, java.io.ObjectInputStream str, V defaultVal) throws java.io.IOException, ClassNotFoundException { // lo 树的第一结点的索引 hi 树的最后一个结点的索引 /* * Strategy: The root is the middlemost element. To get to it, we * have to first recursively construct the entire left subtree, * so as to grab all of its elements. We can then proceed with right * subtree. * * The lo and hi arguments are the minimum and maximum * indices to pull out of the iterator or stream for current subtree. * They are not actually indexed, we just proceed sequentially, * ensuring that items are extracted in corresponding order. */ if (hi < lo) return null; int mid = (lo + hi) >>> 1; // 构建左子树 Entry<K,V> left = null; if (lo < mid) left = buildFromSorted(level+1, lo, mid - 1, redLevel, it, str, defaultVal); // extract key and/or value from iterator or stream // 获取k-v的值 K key; V value; if (it != null) { if (defaultVal==null) { Map.Entry<?,?> entry = (Map.Entry<?,?>)it.next(); key = (K)entry.getKey(); value = (V)entry.getValue(); } else { key = (K)it.next(); value = defaultVal; } } else { // use stream key = (K) str.readObject(); value = (defaultVal != null ? defaultVal : (V) str.readObject()); } // SortedMap中第一个结点作为TreeMap的根结点,默认是黑结点 Entry<K,V> middle = new Entry<>(key, value, null); // color nodes in non-full bottommost level red if (level == redLevel) middle.color = RED; if (left != null) { middle.left = left; left.parent = middle; } // 构建右子树 if (mid < hi) { Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel, it, str, defaultVal); middle.right = right; right.parent = middle; } return middle; }
1、构建左子树,然后新建结点,然后构建右子树
2、最终形成的树是在叶子结点以上是一个满二叉树,所以满足红黑树的性质,叶子结点不满足,所以把叶子结点都染成红色
基本方法
增/改 put
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; // 找到插入结点在红黑树中的位置,如果key相等更新改结点value 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; }
找到插入结点的位置,然后新建结点插入,然后通过fixAfterInsertion调整红黑树的平衡
删 remove
public V remove(Object key) { Entry<K,V> p = getEntry(key); if (p == null) return null; V oldValue = p.value; deleteEntry(p); return oldValue; }
先通过getEntry找到树结点,然后通过deleteEntry删除该结点
final Entry<K,V> 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<? 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; }
查 get
public V get(Object key) { Entry<K,V> p = getEntry(key); return (p==null ? null : p.value); }
通过getEntry找到该结点
一些问题
参考
http://blog.csdn.net/ns_code/article/details/36421085
http://blog.csdn.net/jiang_bing/article/details/7537803