【JDK8】HashMap集合 原始碼閱讀
阿新 • • 發佈:2018-11-26
JDK8的HashMap資料結構上覆雜了很多,因此讀取效率得以大大提升,關於原始碼中紅黑樹的增刪改查,博主沒有細讀,會在下一篇博文中使用Java實現紅黑樹的增刪改查。
下面是類的結構圖:
程式碼(摘抄自JDK):
import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.*; /** * hashMap * 作為Kit ,保證健壯、高效,然後才是可閱讀性 * http://www.mamicode.com/info-detail-2219646.html * java紅黑樹: * http://www.cnblogs.com/skywang12345/p/3624343.html * hashMap中概念解讀 * https://blog.csdn.net/fan2012huan/article/details/51087722 * hashmap解讀: * https://blog.csdn.net/AJ1101/article/details/79413939#commentBox * <p> * 概念摘抄: * 約定前面的陣列結構的每一個格格稱為桶 * 約定桶後面存放的每一個數據稱為bin * bin這個術語來自於JDK 1.8的HashMap註釋。 * * @param <K> * @param <V> * @author jdk */ public class HappyMap<K, V> extends HashMap<K, V> implements Map<K, V> { /** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; /** * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<30. * 最大容量,如果一個更高的值被建構函式用引數隱式指定,那麼依舊使用這個容量 * <p> * 必須是2的次方 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * 當沒有在建構函式裡面指定,將使用這個預設負載因子 * The load factor used when none specified in constructor */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * The bin count threshold for using a tree rather than list for a * bin. Bins are converted to trees when adding an element to a * bin with at least this many nodes. The value must be greater * than 2 and should be at least 8 to mesh with assumptions in * tree removal about conversion back to plain bins upon * shrinkage. * 一個bucket的樹化閾值(紅黑樹) * <p> * 為bin使用tree還是list一個bin數目閾值。在至少達到這個數目節點的情況下增加元素,bins將會轉化成tree。該值必須大於2,至少應該是8,與移除樹的假設相適應。 */ static final int TREEIFY_THRESHOLD = 8; /** * The bin count threshold for untreeifying a (split) bin during a * resize operation. Should be less than TREEIFY_THRESHOLD, and at * most 6 to mesh with shrinkage detection under removal. * 一個樹的連結串列還原閾值 * <p> * 在調整大小操作時反樹化(切分)一個bin的bin數目閾值,在移除時檢測最大是6。 */ static final int UNTREEIFY_THRESHOLD = 6; /** * The smallest table capacity for which bins may be treeified. * (Otherwise the table is resized if too many nodes in a bin.) * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts * between resizing and treeification thresholds. * 樹形化時bins的最小雜湊表容量(否則如果bin中有太多的節點就對雜湊表調整大小)。 * 為避免在調整大小和樹形化閾值之間產生矛盾,這個值至少是4 * TREEIFY_THERSHOLD。 */ static final int MIN_TREEIFY_CAPACITY = 64; /** * NODE-use HashMap * Basic hash bin node, used for most entries. (See below for * TreeNode subclass, and in LinkedHashMap for its Entry subclass.) */ static class Node<K, V> implements Map.Entry<K, V> { final int hash; final K key; V value; HappyMap.Node<K, V> next; Node(int hash, K key, V value, HappyMap.Node<K, V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } @Override public final K getKey() { return key; } @Override public final V getValue() { return value; } @Override public final String toString() { return key + "=" + value; } @Override public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } @Override public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } @Override public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry<?, ?> e = (Map.Entry<?, ?>) o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; } } /** * Create a tree bin node */ HappyMap.TreeNode<K, V> newTreeNode(int hash, K key, V value, HappyMap.Node<K, V> next) { return new HappyMap.TreeNode<>(hash, key, value, next); } /* ---------------- Static utilities(沒抄) -------------- */ /* ---------------- Fields -------------- */ /** * The table, initialized on first use, and resized as * necessary. When allocated, length is always a power of two. * (We also tolerate length zero in some operations to allow * bootstrapping mechanics that are currently not needed.) */ transient HappyMap.Node<K, V>[] table; /** * Holds cached entrySet(). Note that AbstractMap fields are used * for keySet() and values(). */ transient Set<Map.Entry<K, V>> entrySet; /** * The number of key-value mappings contained in this map. */ transient int size; /** * The number of times this HashMap has been structurally modified * Structural modifications are those that change the number of mappings in * the HashMap or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the HashMap fail-fast. (See ConcurrentModificationException). */ transient int modCount; /** * The next size value at which to resize (capacity * load factor). * threshold表示當HashMap的size大於threshold時會執行resize操作。 * threshold=capacity*loadFactor * * @serial */ // (The javadoc description is true upon serialization. // Additionally, if the table array has not been allocated, this // field holds the initial array capacity, or zero signifying // DEFAULT_INITIAL_CAPACITY.) int threshold; /** * The load factor for the hash table. * * @serial */ final float loadFactor; /** * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ public HappyMap() { // all other fields defaulted this.loadFactor = DEFAULT_LOAD_FACTOR; } /* ---------------- Public operations -------------- */ @Override public Set<Entry<K, V>> entrySet() { return null; } /** * Returns the number of key-value mappings in this map. * * @return the number of key-value mappings in this map */ @Override public int size() { return size; } /** * Returns <tt>true</tt> if this map contains no key-value mappings. * * @return <tt>true</tt> if this map contains no key-value mappings */ @Override public boolean isEmpty() { return size == 0; } /** * Computes key.hashCode() and spreads (XORs) higher bits of hash * to lower. Because the table uses power-of-two masking, sets of * hashes that vary only in bits above the current mask will * always collide. (Among known examples are sets of Float keys * holding consecutive whole numbers in small tables.) So we * apply a transform that spreads the impact of higher bits * downward. There is a tradeoff between speed, utility, and * quality of bit-spreading. Because many common sets of hashes * are already reasonably distributed (so don't benefit from * spreading), and because we use trees to handle large sets of * collisions in bins, we just XOR some shifted bits in the * cheapest possible way to reduce systematic lossage, as well as * to incorporate impact of the highest bits that would otherwise * never be used in index calculations because of table bounds. */ static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } /** * 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 <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ @Override public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { HappyMap.Node<K, V>[] tab; HappyMap.Node<K, V> calPosiNode; int tabLenth, position; //如果 table屬性 為空,初始化定義大小,返回新的長度(初始化長度) if ((tab = table) == null || (tabLenth = tab.length) == 0) { tabLenth = (tab = resize()).length; } //hash(key)&(n-1)查詢位置,如果位置上的Node為null,新建一個Node if ((calPosiNode = tab[position = (tabLenth - 1) & hash]) == null) { tab[position] = newNode(hash, key, value, null); } else {//如果位置上有Node了 HappyMap.Node<K, V> tempNode; K k; //新舊元素key值相等(或雜湊值相同,地址相等),覆蓋 if (calPosiNode.hash == hash && ((k = calPosiNode.key) == key || (key != null && key.equals(k)))) { tempNode = calPosiNode; //如果key不相等且是此位置上的RB樹節點 } else if (calPosiNode instanceof HappyMap.TreeNode) { tempNode = ((HappyMap.TreeNode<K, V>) calPosiNode).putTreeVal(this, tab, hash, key, value); } else {//key 不相等 且非RB樹節點 for (int binCount = 0; ; ++binCount) { // 當連結串列只有一個頭部結點,則新建(append)一個結點 if ((tempNode = calPosiNode.next) == null) { calPosiNode.next = newNode(hash, key, value, null); // 連結串列長度大於8(0 to 7)時,將連結串列轉紅黑樹 if (binCount >= TREEIFY_THRESHOLD - 1) { treeifyBin(tab, hash); } break; } if (tempNode.hash == hash && ((k = tempNode.key) == key || (key != null && key.equals(k)))) { break; } //更新 calPosiNode = tempNode; } } // existing mapping for key if (tempNode != null) { V oldValue = tempNode.value; if (!onlyIfAbsent || oldValue == null) { tempNode.value = value; } afterNodeAccess(tempNode); return oldValue; } } ++modCount; if (++size > threshold) { resize(); } afterNodeInsertion(evict); return null; } // Callbacks to allow LinkedHashMap post-actions void afterNodeAccess(HappyMap.Node<K, V> p) { } void afterNodeInsertion(boolean evict) { } /** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field threshold. * Otherwise, because we are using power-of-two expansion, the * elements from each bin must either stay at same index, or move * with a power of two offset in the new table. * 初始化或者擴容之後元素調整 * * @return the table */ final HappyMap.Node<K, V>[] resize() { HappyMap.Node<K, V>[] oldTab = table; //原陣列長度 int oldCap = (oldTab == null) ? 0 : oldTab.length; //原擴充臨界值 int oldThr = threshold; int newCap, newThr = 0; //table不為空 if (oldCap > 0) { //如果陣列長度達到最大值,則修改臨界值為Integer.MAX_VALUE if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } //沒有達到最大值則容量*2 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) { // doubles threshold newThr = oldThr << 1; } } // initial capacity was placed in threshold(直接賦值) else if (oldThr > 0) { newCap = oldThr; } // zero initial threshold signifies using defaults(初始化容量與邊界) else { newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) { float ft = (float) newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ? (int) ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes", "unchecked"}) HappyMap.Node<K, V>[] newTab = (HappyMap.Node<K, V>[]) new HappyMap.Node[newCap]; table = newTab; // 調整陣列大小之後,需要調整紅黑樹或者連結串列的指向 if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { HappyMap.Node<K, V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) { newTab[e.hash & (newCap - 1)] = e; } // 紅黑樹調整 else if (e instanceof HappyMap.TreeNode) { ((HappyMap.TreeNode<K, V>) e).split(this, newTab, j, oldCap); } // preserve order連結串列順序調整 else { HappyMap.Node<K, V> loHead = null, loTail = null; HappyMap.Node<K, V> hiHead = null, hiTail = null; HappyMap.Node<K, V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; } // Create a regular (non-tree) node HappyMap.Node<K, V> newNode(int hash, K key, V value, HappyMap.Node<K, V> next) { return new HappyMap.Node<>(hash, key, value, next); } // For conversion from TreeNodes to plain nodes HappyMap.Node<K, V> replacementNode(HappyMap.Node<K, V> p, HappyMap.Node<K, V> next) { return new HappyMap.Node<>(p.hash, p.key, p.value, next); } /** * Replaces all linked nodes in bin at index for given hash unless * table is too small, in which case resizes instead. * bin(Node)轉換為 TreeNode */ final void treeifyBin(HappyMap.Node<K, V>[] tab, int hash) { int n, index; HappyMap.Node<K, V> e; if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) { resize(); } else if ((e = tab[index = (n - 1) & hash]) != null) { HappyMap.TreeNode<K, V> hd = null, tl = null; do { //Node轉TreeNode HappyMap.TreeNode<K, V> p = replacementTreeNode(e, null); if (tl == null) { hd = p; } else { p.prev = tl; tl.next = p; } tl = p; } while ((e = e.next) != null); if ((tab[index] = hd) != null) { //轉為紅黑樹 hd.treeify(tab); } } } // For treeifyBin HappyMap.TreeNode<K, V> replacementTreeNode(HappyMap.Node<K, V> p, HappyMap.Node<K, V> next) { return new HappyMap.TreeNode<>(p.hash, p.key, p.value, next); } /** * HashMap.Node subclass for normal LinkedHashMap entries. */ /* ------------------------------------------------------------ */ /** * Returns x's Class if it is of the form "class C implements * Comparable<C>", else null. */ static Class<?> comparableClassFor(Object x) { if (x instanceof Comparable) { Class<?> c; Type[] ts, as; Type t; ParameterizedType p; if ((c = x.getClass()) == String.class) // bypass checks return c; if ((ts = c.getGenericInterfaces()) != null) { for (int i = 0; i < ts.length; ++i) { if (((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType) t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c return c; } } } return null; } /** * Returns k.compareTo(x) if x matches kc (k's screened comparable * class), else 0. */ @SuppressWarnings({"rawtypes", "unchecked"}) // for cast to Comparable static int compareComparables(Class<?> kc, Object k, Object x) { return (x == null || x.getClass() != kc ? 0 : ((Comparable) k).compareTo(x)); } /** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * <p>More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) * * <p>A return value of {@code null} does not <i>necessarily</i> * 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. * * @see #put(Object, Object) */ @Override public V get(Object key) { HappyMap.Node<K, V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } /** * Implements Map.get and related methods * * @param hash hash for key * @param key the key * @return the node, or null if none */ final HappyMap.Node<K, V> getNode(int hash, Object key) { HappyMap.Node<K, V>[] tab; HappyMap.Node<K, V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof HappyMap.TreeNode) return ((HappyMap.TreeNode<K, V>) first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; } // Tree bins /** * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn * extends Node) so can be used as extension of either regular or * linked node. */ static final class TreeNode<K, V> extends HappyMap.Node<K, V> { HappyMap.Entry<K, V> before, after; // TreeNode(int hash, K key, V value, HappyMap.Node<K,V> next) { // super(hash, key, value, next); // } HappyMap.TreeNode<K, V> parent; // red-black tree links HappyMap.TreeNode<K, V> left; HappyMap.TreeNode<K, V> right; HappyMap.TreeNode<K, V> prev; // needed to unlink next upon deletion boolean red; TreeNode(int hash, K key, V val, HappyMap.Node<K, V> next) { super(hash, key, val, next); } /** * Returns root of tree containing this node. */ final HappyMap.TreeNode<K, V> root() { for (HappyMap.TreeNode<K, V> r = this, p; ; ) { if ((p = r.parent) == null) return r; r = p; } } /** * Ensures that the given root is the first node of its bin. */ static <K, V> void moveRootToFront(HappyMap.Node<K, V>[] tab, HappyMap.TreeNode<K, V> root) { int n; if (root != null && tab != null && (n = tab.length) > 0) { int index = (n - 1) & root.hash; HappyMap.TreeNode<K, V> first = (HappyMap.TreeNode<K, V>) tab[index]; if (root != first) { HappyMap.Node<K, V> rn; tab[index] = root; HappyMap.TreeNode<K, V> rp = root.prev; if ((rn = root.next) != null) ((HappyMap.TreeNode<K, V>) rn).prev = rp; if (rp != null) rp.next = rn; if (first != null) first.prev = root; root.next = first; root.prev = null; } assert checkInvariants(root); } } /** * Finds the node starting at root p with the given hash and key. * The kc argument caches comparableClassFor(key) upon first use * comparing keys. */ final HappyMap.TreeNode<K, V> find(int h, Object k, Class<?> kc) { HappyMap.TreeNode<K, V> p = this; do { int ph, dir; K pk; HappyMap.TreeNode<K, V> pl = p.left, pr = p.right, q; if ((ph = p.hash) > h) p = pl; else if (ph < h) p = pr; else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; else if (pl == null) p = pr; else if (pr == null) p = pl; else if ((kc != null || (kc = comparableClassFor(k)) != null) && (dir = compareComparables(kc, k, pk)) != 0) p = (dir < 0) ? pl : pr; else if ((q = pr.find(h, k, kc)) != null) return q; else p = pl; } while (p != null); return null; } /** * Calls find for root node. */ final HappyMap.TreeNode<K, V> getTreeNode(int h, Object k) { return ((parent != null) ? root() : this).find(h, k, null); } /** * Tie-breaking utility for ordering insertions when equal * hashCodes and non-comparable. We don't require a total * order, just a consistent insertion rule to maintain * equivalence across rebalancings. Tie-breaking further than * necessary simplifies testing a bit. */ static int tieBreakOrder(Object a, Object b) { int d; if (a == null || b == null || (d = a.getClass().getName(). compareTo(b.getClass().getName())) == 0) d = (System.identityHashCode(a) <= System.identityHashCode(b) ? -1 : 1); return d; } /** * Forms tree of the nodes linked from this node. * 將連結串列中每個值進行紅黑樹插入操作 * * @return root of tree */ final void treeify(HappyMap.Node<K, V>[] tab) { HappyMap.TreeNode<K, V> root = null; for (HappyMap.TreeNode<K, V> x = this, next; x != null; x = next) { next = (HappyMap.TreeNode<K, V>) x.next; // 初始化Root x.left = x.right = null; if (root == null) { x.parent = null; x.red = false; root = x; } else { K k = x.key; int h = x.hash; Class<?> kc = null; //TREENODE節點插入 for (HappyMap.TreeNode<K, V> p = root; ; ) { int dir, ph; K pk = p.key; if ((ph = p.hash) > h) { dir = -1; } else if (ph < h) { dir = 1; } else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) { dir = tieBreakOrder(k, pk); } HappyMap.TreeNode<K, V> xp = p; if ((p = (dir <= 0) ? p.left : p.right) == null) { x.parent = xp; if (dir <= 0) xp.left = x; else xp.right = x; root = balanceInsertion(root, x); break; } } } } moveRootToFront(tab, root); } /** * Returns a list of non-TreeNodes replacing those linked from * this node. */ final HappyMap.Node<K, V> untreeify(HappyMap<K, V> map) { HappyMap.Node<K, V> hd = null, tl = null; for (HappyMap.Node<K, V> q = this; q != null; q = q.next) { HappyMap.Node<K, V> p = map.replacementNode(q, null); if (tl == null) hd = p; else tl.next = p; tl = p; } return hd; } /** * Tree version of putVal. * 紅黑樹節點插入 */ final HappyMap.TreeNode<K, V> putTreeVal(HappyMap<K, V> map, HappyMap.Node<K, V>[] tab, int h, K k, V v) { Class<?> kc = null; boolean searched = false; HappyMap.TreeNode<K, V> root = (parent != null) ? root() : this; for (HappyMap.TreeNode<K, V> p = root; ; ) { int dir, ph; K pk; if ((ph = p.hash) > h) dir = -1; else if (ph < h) dir = 1; else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) { if (!searched) { HappyMap.TreeNode<K, V> q, ch; searched = true; if (((ch = p.left) != null && (q = ch.find(h, k, kc)) != null) || ((ch = p.right) != null && (q = ch.find(h, k, kc)) != null)) return q; } dir = tieBreakOrder(k, pk); } HappyMap.TreeNode<K, V> xp = p; if ((p = (dir <= 0) ? p.left : p.right) == null) { HappyMap.Node<K, V> xpn = xp.next; HappyMap.TreeNode<K, V> x = map.newTreeNode(h, k, v, xpn); if (dir <= 0) xp.left = x; else xp.right = x; xp.next = x; x.parent = x.prev = xp; if (xpn != null) ((HappyMap.TreeNode<K, V>) xpn).prev = x; moveRootToFront(tab, balanceInsertion(root, x)); return null; } } } /** * Removes the given node, that must be present before this call. * This is messier than typical red-black deletion code because we * cannot swap the contents of an interior node with a leaf * successor that is pinned by "next" pointers that are accessible * independently during traversal. So instead we swap the tree * linkages. If the current tree appears to have too few nodes, * the bin is converted back to a plain bin. (The test triggers * somewhere between 2 and 6 nodes, depending on tree structure). */ final void removeTreeNode(HappyMap<K, V> map, HappyMap.Node<K, V>[] tab, boolean movable) { int n; if (tab == null || (n = tab.length) == 0) return; int index = (n - 1) & hash; HappyMap.TreeNode<K, V> first = (HappyMap.TreeNode<K, V>) tab[index], root = first, rl; HappyMap.TreeNode<K, V> succ = (HappyMap.TreeNode<K, V>) next, pred = prev; if (pred == null) tab[index] = first = succ; else pred.next = succ; if (succ != null) succ.prev = pred; if (first == null) return; if (root.parent != null) root = root.root(); if (root == null || root.right == null || (rl = root.left) == null || rl.left == null) { tab[index] = first.untreeify(map); // too small return; } HappyMap.TreeNode<K, V> p = this, pl = left, pr = right, replacement; if (pl != null && pr != null) { HappyMap.TreeNode<K, V> s = pr, sl; while ((sl = s.left) != null) // find successor s = sl; boolean c = s.red; s.red = p.red; p.red = c; // swap colors HappyMap.TreeNode<K, V> sr = s.right; HappyMap.TreeNode<K, V> pp = p.parent; if (s == pr) { // p was s's direct parent p.parent = s; s.right = p; } else { HappyMap.TreeNode<K, V> sp = s.parent; if ((p.parent = sp) != null) { if (s == sp.left) sp.left = p; else sp.right = p; } if ((s.right = pr) != null) pr.parent = s; } p.left = null; if ((p.right = sr) != null) sr.parent = p; if ((s.left = pl) != null) pl.parent = s; if ((s.parent = pp) == null) root = s; else if (p == pp.left) pp.left = s; else pp.right = s; if (sr != null) replacement = sr; else replacement = p; } else if (pl != null) replacement = pl; else if (pr != null) replacement = pr; else replacement = p; if (replacement != p) { HappyMap.TreeNode<K, V> pp = replacement.parent = p.parent; if (pp == null) root = replacement; else if (p == pp.left) pp.left = replacement; else pp.right = replacement; p.left = p.right = p.parent = null; } HappyMap.TreeNode<K, V> r = p.red ? root : balanceDeletion(root, replacement); if (replacement == p) { // detach HappyMap.TreeNode<K, V> pp = p.parent; p.parent = null; if (pp != null) { if (p == pp.left) pp.left = null; else if (p == pp.right) pp.right = null; } } if (movable) moveRootToFront(tab, r); } /** * Splits nodes in a tree bin into lower and upper tree bins, * or untreeifies if now too small. Called only from resize; * see above discussion about split bits and indices. * * @param map the map * @param tab the table for recording bin heads * @param index the index of the table being split * @param bit the bit of hash to split on */ final void split(HappyMap<K, V> map, HappyMap.Node<K, V>[] tab, int index, int bit) { HappyMap.TreeNode<K, V> b = this; // Relink into lo and hi lists, preserving order HappyMap.TreeNode<K, V> loHead = null, loTail = null; HappyMap.TreeNode<K, V> hiHead = null, hiTail = null; int lc = 0, hc = 0; for (HappyMap.TreeNode<K, V> e = b, next; e != null; e = next) { next = (HappyMap.TreeNode<K, V>) e.next; e.next = null; if ((e.hash & bit) == 0) { if ((e.prev = loTail) == null) loHead = e; else loTail.next = e; loTail = e; ++lc; } else { if ((e.prev = hiTail) == null) hiHead = e; else hiTail.next = e; hiTail = e; ++hc; } } if (loHead != null) { if (lc <= UNTREEIFY_THRESHOLD) tab[index] = loHead.untreeify(map); else { tab[index] = loHead; if (hiHead != null) // (else is already treeified) loHead.treeify(tab); } } if (hiHead != null) { if (hc <= UNTREEIFY_THRESHOLD) tab[index + bit] = hiHead.untreeify(map); else { tab[index + bit] = hiHead; if (loHead != null) hiHead.treeify(tab); } } } /* ------------------------------------------------------------ */ // Red-black tree methods, all adapted from CLR static <K, V> HappyMap.TreeNode<K, V> rotateLeft(HappyMap.TreeNode<K, V> root, HappyMap.TreeNode<K, V> p) { HappyMap.TreeNode<K, V> r, pp, rl; if (p != null && (r = p.right) != null) { if ((rl = p.right = r.left) != null) rl.parent = p; if ((pp = r.parent = p.parent) == null) (root = r).red = false; else if (pp.left == p) pp.left = r; else pp.right = r; r.left = p; p.parent = r; } return root; } static <K, V> HappyMap.TreeNode<K, V> rotateRight(HappyMap.TreeNode<K, V> root, HappyMap.TreeNode<K, V> p) { HappyMap.TreeNode<K, V> l, pp, lr; if (p != null && (l = p.left) != null) { if ((lr = p.left = l.right) != null) lr.parent = p; if ((pp = l.parent = p.parent) == null) (root = l).red = false; else if (pp.right == p) pp.right = l; else pp.left = l; l.right = p; p.parent = l; } return root; } /** * 插入後的平衡操作 * * @param root * @param x * @param <K> * @param <V> * @return */ static <K, V> HappyMap.TreeNode<K, V> balanceInsertion(HappyMap.TreeNode<K, V> root, HappyMap.TreeNode<K, V> x) { x.red = true; for (HappyMap.TreeNode<K, V> xp, xpp, xppl, xppr; ; ) { //空 if ((xp = x.parent) == null) { x.red = false; return x; } //root else if (!xp.red || (xpp = xp.parent) == null) { return root; } //左子樹插入 if (xp == (xppl = xpp.left)) { if ((xppr = xpp.right) != null && xppr.red) { xppr.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.right) { root = rotateLeft(root, x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; root = rotateRight(root, xpp); } } } } else { //右子樹插入 // 祖父結點不為空,並且顏色為紅色時 if (xppl != null && xppl.red) { xppl.red = false; xp.red = false; xpp.red = true; x = xpp; } else { // 左子樹插入 if (x == xp.left) { root = rotateRight(root, x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } // x 的父親結點設定成黑色 if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; // 左旋 root = rotateLeft(root, xpp); } } } } } } static <K, V> HappyMap.TreeNode<K, V> balanceDeletion(HappyMap.TreeNode<K, V> root, HappyMap.TreeNode<K, V> x) { for (HappyMap.TreeNode<K, V> xp, xpl, xpr; ; ) { if (x == null || x == root) return root; else if ((xp = x.parent) == null) { x.red = false; return x; } else if (x.red) { x.red = false; return root; } else if ((xpl = xp.left) == x) { if ((xpr = xp.right) != null && xpr.red) { xpr.red = false; xp.red = true; root = rotateLeft(root, xp); xpr = (xp = x.parent) == null ? null : xp.right; } if (xpr == null) x = xp; else { HappyMap.TreeNode<K, V> sl = xpr.left, sr = xpr.right; if ((sr == null || !sr.red) && (sl == null || !sl.red)) { xpr.red = true; x = xp; } else { if (sr == null || !sr.red) { if (sl != null) sl.red = false; xpr.red = true; root = rotateRight(root, xpr); xpr = (xp = x.parent) == null ? null : xp.right; } if (xpr != null) { xpr.red = (xp == null) ? false : xp.red; if ((sr = xpr.right) != null) sr.red = false; } if (xp != null) { xp.red = false; root = rotateLeft(root, xp); } x = root; } } } else { // symmetric if (xpl != null && xpl.red) { xpl.red = false; xp.red = true; root = rotateRight(root, xp); xpl = (xp = x.parent) == null ? null : xp.left; } if (xpl == null) x = xp; else { HappyMap.TreeNode<K, V> sl = xpl.left, sr = xpl.right; if ((sl == null || !sl.red) && (sr == null || !sr.red)) { xpl.red = true; x = xp; } else { if (sl == null || !sl.red) { if (sr != null) sr.red = false; xpl.red = true; root = rotateLeft(root, xpl); xpl = (xp = x.parent) == null ? null : xp.left; } if (xpl != null) { xpl.red = (xp == null) ? false : xp.red; if ((sl = xpl.left) != null) sl.red = false; } if (xp != null) { xp.red = false; root = rotateRight(root, xp); } x = root; } } } } } /** * Recursive invariant check */ static <K, V> boolean checkInvariants(HappyMap.TreeNode<K, V> t) { HappyMap.TreeNode<K, V> tp = t.parent, tl = t.left, tr = t.right, tb = t.prev, tn = (HappyMap.TreeNode<K, V>) t.next; if (tb != null && tb.next != t) return false; if (tn != null && tn.prev != t) return false; if (tp != null && t != tp.left && t != tp.right) return false; if (tl != null && (tl.parent != t || tl.hash > t.hash)) return false; if (tr != null && (tr.parent != t || tr.hash < t.hash)) return false; if (t.red && tl != null && tl.red && tr != null && tr.red) return false; if (tl != null && !checkInvariants(tl)) return false; if (tr != null && !checkInvariants(tr)) return false; return true; } } }