遍历
TreeMap 使用中序遍历, 遍历的方式与 HashMap, LinkedHashMap 相同, 通过 entrySet().iterator() 方法返回 Iterator 实例遍历.1
2
3
4public Set<Map.Entry<K,V>> entrySet() {
EntrySet es = entrySet;
return (es != null) ? es : (entrySet = new EntrySet());
}
1 | // 迭代器和 TreeMap 实例绑定一起, 所以用非静态内部类 |
1 | final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> { |
PrivateEntryIterator
1 | /** |
successor
TreeMap 之所以用中序遍历来迭代, 是因为左子树比节点要小, 右子树比节点要大, 只有中序遍历方式才会输出从小到大的节点. 在前面已经把最左节点传入给迭代器了, 这是遍历开始的第一个节点, 接下来主要工作就是如何确认节点的后继, 可以分两种情况讨论:
- 节点有右子树
该节点的后继就是它右子树的最左节点, 如下图, 0005 节点的后继就是 0008. - 节点没有右子树
该节点的后继就是它所在的左子树的第一个父节点, 如下图, 0006 节点的后继就是 0007. 而如果向上追溯发现该节点不是处于左子树, 那么这个节点就是最后节点, 如 0009 就是最后节点.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
if (t == null)
return null;
// 有右子树, 对右子树进行最左遍历, 返回最左节点
else if (t.right != null) {
Entry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
}
// 没有右子树, 向上追溯第一个左子树节点
else {
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
// 这里通过节点是否父节点的右子树来找到第一个左子树
// 如果 p 为空, 说明已经追溯到根节点了, 没有后继了, 直接返回空值 p
// 如果 ch != p.right, 说明 ch 是 p 的左孩子, p 就是要找的后继了
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
如果有疑问欢迎来 Issues 探讨