特性
- 底层是红黑树,算法基于经典书籍 《Introduction to Algorithm》
- key 需要实现
comparable
接口,或者提供comparator
- Views:
- EntrySet: Set OF Map.Enty OF Key-Value
- Value : Collection Of Value
- KeySet : Set - 所有的遍历基于上面提供的三种视图,返回的所有pair OF key-value 不 支持 pair.setValue
- 提供了基于sortedMap的三种子视图:
- subMap: from,to
- headMap
- tailMap - 的增删改查, 以及
Methods {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry}, and {@code higherEntry} return {@code Map.Entry} objects associated with keys respectively less than, less than or equal,greater than or equal, and greater than a given key, returning {@code null} if there is no such key
后面是一些源码上的收获
higherEntry,ceilingEntry
这两个的区别一个是严格大,另外一个是大于等于,在代码上仅体现在一行。
final Entry<K,V> getCeilingEntry(K key) {
Entry<K,V> p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp < 0) {
if (p.left != null)
p = p.left;
else
return p;// p > key
} else if (cmp > 0) {// 严格大于
if (p.right != null) {
p = p.right;
} else {
Entry<K,V> parent = p.parent;
Entry<K,V> ch = p;
while (parent != null && ch == parent.right) {//最近的左孩子一侧下来
ch = parent;
parent = parent.parent;
}
return parent;
}
} else // 等于
return p;
}
return null;
}
看那个else
final Entry<K,V> getHigherEntry(K key) {
Entry<K,V> p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp < 0) {
if (p.left != null)
p = p.left;
else
return p;
} else {//找严格大于
if (p.right != null) {
p = p.right;
} else {
Entry<K,V> parent = p.parent;
Entry<K,V> ch = p;
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
}
return parent;
}
}
}
return null;
}
迭代器的时间复杂度
值得说的是迭代器的方法 next
的时间复杂度并不是 O(1)
的,因为他没有像HashMap中的树箱一样,提供next索引到下一个,而是通过一个Successer或者pre方法求的下一个,所以这里的复杂度是当前迭代器的树高。不过值得庆幸的是由于红黑树的高度平衡的特性,遍历完整棵树的复杂度还是
的,不过常数比较高,(这里我口胡了一下,并没有证明,我是想到了由堆的直接创建方法计算中的复杂度是
,这里红黑树的高度平衡性,完全可以同过补节点的方法,让他是完全二叉的,)。
final Entry<K,V> nextEntry() {
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
next = successor(e);//访问e的后继
lastReturned = e;
return e;
}
疑问
comparable和comparator两种比较方式,源代码中大量用到了,两种不同的比较方式,我认为完全可以在key是comparable而没有提供comparator的时候,将其封装出一个comparator从而让后续代码都基于一种比较方式,做更简单的设计,不知作者这样做到底能带来多大的时间上的优化。
比如get方法中的
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}