在学习GSON的过程中,发现了GSON的基础数据类型LinkedTreeMap,因此展开学习。
private final LinkedTreeMap members =
new LinkedTreeMap();
LinkedTreeMap,一切如此的熟悉,在jdk中有LinkedMap有TreeMap有TreeMap,这个LinkedTreeMap是个什么,顾名思义,这应该是一个连续的且有序的集合。
package com.google.gson.internal;
一看包名,这是google自己实现的map。
Node parent;
Node left;
Node right;
Node next;
Node prev;
final K key;
V value;
int height;
咋一看,这是啥啊。一个结点包含了父节点,左右结点和前后结点,但是不要慌我们接着往下看。
接着回到LinkedTreeMap,在类的最开时定义了一个比较器NATURAL_ORDER
private static final Comparator NATURAL_ORDER = new Comparator() {
public int compare(Comparable a, Comparable b) {
return a.compareTo(b);
}
};
这个比较器在构造LinkHashMap时传入,如果传入的比较器是空(该类没有实现Comparator)则使用NATURAL_ORDER 比较器进行比较,此处略微介绍Comparator和Comparable的区别,实现Comparable 接口的类即支持排序(因为实现了CompareTo)方法,而如果一个类不支持排序(没有实现Compareable接口)则可以使用Comparator比较器来实现比较方法。
为什么要先介绍这个比较器呢,因为在LinkTreeMap进行新增结点和查找结点都需要使用到这个比较器,在find()方法里,首先判断根节点是否为空。
Node find(K key, boolean create) {
Node nearest = root;
if (nearest != null) {
Comparable
当根节点不为空时,判断比较器是否为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 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(nearest, key, header, header.prev);
root = created;
new Node干的事
/** Create a regular entry */
Node(Node parent, K key, Node next, Node 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(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 unbalanced, boolean insert) {
for (Node node = unbalanced; node != null; node = node.parent) {
进入方法后就开始遍历结点,遍历规则是当结点父节点不为空时,无限循环。
Node left = node.left;
Node 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 rightLeft = right.left;
Node 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时根据左右高度差进行旋转,最终的存储结构是一个有插入顺序的链表和排序二叉树