在學習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時根據左右高度差進行旋轉,最終的存儲結構是一個有插入順序的鏈表和排序二叉樹
