在學習GSON的過程中,發現了GSON的基礎數據類型LinkedTreeMap,因此展開學習。
private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap<String, JsonElement>();
LinkedTreeMap,一切如此的熟悉,在jdk中有LinkedMap有TreeMap有TreeMap,這個LinkedTreeMap是個什么,顧名思義,這應該是一個連續的且有序的集合。
package com.google.gson.internal;
一看包名,這是google自己實現的map。
Node<K, V> parent; Node<K, V> left; Node<K, V> right; Node<K, V> next; Node<K, V> prev; final K key; V value; int height;
咋一看,這是啥啊。一個結點包含了父節點,左右結點和前后結點,但是不要慌我們接着往下看。
接着回到LinkedTreeMap,在類的最開時定義了一個比較器NATURAL_ORDER
private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() { public int compare(Comparable a, Comparable b) { return a.compareTo(b); } };
這個比較器在構造LinkHashMap時傳入,如果傳入的比較器是空(該類沒有實現Comparator)則使用NATURAL_ORDER 比較器進行比較,此處略微介紹Comparator和Comparable的區別,實現Comparable 接口的類即支持排序(因為實現了CompareTo)方法,而如果一個類不支持排序(沒有實現Compareable接口)則可以使用Comparator比較器來實現比較方法。
為什么要先介紹這個比較器呢,因為在LinkTreeMap進行新增結點和查找結點都需要使用到這個比較器,在find()方法里,首先判斷根節點是否為空。
Node<K, V> find(K key, boolean create) { Node<K, V> nearest = root; if (nearest != null) { Comparable<Object> comparableKey = (comparator == NATURAL_ORDER) ? (Comparable<Object>) key : null;
當根節點不為空時,判斷比較器是否為LinkTreeMap自定義的比較器,如果是則使用K類的比較器,否則傳null。此處的null主要是標志作用,決定之后使用Compare方法還是使用compareTo方法。
while (true) { comparison = (comparableKey != null) ? comparableKey.compareTo(nearest.key) : comparator.compare(key, nearest.key); // We found the requested key. if (comparison == 0) { return nearest; } // If it exists, the key is in a subtree. Go deeper. Node<K, V> child = (comparison < 0) ? nearest.left : nearest.right; if (child == null) { break; } nearest = child; }
在這循環中根據返回值判斷要尋找的結點可能存在的位置,當值比比較的結點小時在他的左子樹上繼續查找,反之查詢右子樹直到找到或者當前對象為空。
緊接着,如果create為false則結束find方法,此時nearest就是要查找的值或者根節點。
如果create為true則創建結點,且nearest為null,nearest為null只有一種情況:當前樹是一個空樹
created = new Node<K, V>(nearest, key, header, header.prev); root = created;
new Node干的事
/** Create a regular entry */ Node(Node<K, V> parent, K key, Node<K, V> next, Node<K, V> prev) { this.parent = parent; this.key = key; this.height = 1; this.next = next; this.prev = prev; prev.next = this; next.prev = this; }
當樹不是空樹時則根據最后一次比較的結果進行插入。
else { created = new Node<K, V>(nearest, key, header, header.prev); if (comparison < 0) { // nearest.key is higher nearest.left = created; } else { // comparison > 0, nearest.key is lower nearest.right = created; } rebalance(nearest, true); }
進行調整。
private void rebalance(Node<K, V> unbalanced, boolean insert) { for (Node<K, V> node = unbalanced; node != null; node = node.parent) {
進入方法后就開始遍歷結點,遍歷規則是當結點父節點不為空時,無限循環。
Node<K, V> left = node.left; Node<K, V> right = node.right; int leftHeight = left != null ? left.height : 0; int rightHeight = right != null ? right.height : 0; int delta = leftHeight - rightHeight;
保存結點的左右結點以及高度,並計算高度差。
if (delta == -2) { Node<K, V> rightLeft = right.left; Node<K, V> rightRight = right.right; int rightRightHeight = rightRight != null ? rightRight.height : 0; int rightLeftHeight = rightLeft != null ? rightLeft.height : 0; int rightDelta = rightLeftHeight - rightRightHeight; if (rightDelta == -1 || (rightDelta == 0 && !insert)) { rotateLeft(node); // AVL right right } else { assert (rightDelta == 1); rotateRight(right); // AVL right left rotateLeft(node); } if (insert) { break; // no further rotations will be necessary } }
當左節點比右結點低2時,保存右左結點,右右結點,右左結點高度,右右結點高度,並計算高度差。當高度等於1或等於0時進行左旋。當高度差為1是進行右結點右旋,根節點左旋。
當右節點比左結點低2時,反之。
當高度差為0時,修改節點高度。
else if (delta == 0) { node.height = leftHeight + 1; // leftHeight == rightHeight if (insert) { break; // the insert caused balance, so rebalancing is done! } }
當左右節點差為1時,設置高度為左右結點高度更高者加一。以高度差作為約束,約束左右結點高度差不高於2,當等於2時根據左右高度差進行旋轉,最終的存儲結構是一個有插入順序的鏈表和排序二叉樹