今天晚上准备看下HashMap里面,当桶中元素达到阀值转为树型结构中的一些函数。
下面是TreeNode节点的定义:
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red; //节点颜色
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
由上可以看出来这里采用的红黑树作为基本的数据结构,而红黑树的讲解这里不做详述,可参见其他文章。(当时看红黑树的操作,也是看了很久才弄明白,关键是要一气呵成,不能怕,这样就能够看懂了。)
下面我们先看当一个桶中元素超过阀值的时候,将该桶的元素变为树形结构的代码:
final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
// 首先将该桶中的元素中的节点转为树形节点,仍然用一个引用pre将所有的节点链接起来,形成一个以head为头结点,tail为尾节点的串。
do {
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) // 将这个树形节点的链表转为树结构 treeify(tab)
hd.treeify(tab);
}
}
下面是将一个树形节点的链表转为红黑树的过程。
Forms tree of the nodes linked from this node.
final void treeify(Node<K,V>[] tab) {
TreeNode<K,V> root = null;
for (TreeNode<K,V> x = this, next; x != null; x = next) {
next = (TreeNode<K,V>)x.next;
x.left = x.right = null;
if (root == null) { // 若根节点为null.
x.parent = null;
x.red = false;
root = x;
}
else { // 如果根节点不为空,则插入当前元素,红黑树节点的插入
K k = x.key;
int h = x.hash;
Class<?> kc = null;
for (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);
// 插入到叶子节点
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);
}
恩,大致思路就是这样。其中红黑树的操作蛮重要的。