1.简介
JDK1.8中TreeMap底层实现采用了红黑树,具有比较好的查询、添加、删除效率,TreeSet底层实现其实也是TreeMap。另外,红黑树在HashMap中也有运用。
2.红黑树
红黑树是一种二叉查找树,比起一般的二叉查找树,它的添加和删除操作后可以通过自平衡,保证整棵树大致平衡(非绝对平衡),极端情况最长路径是最短路径的2倍(最短路径全是黑节点,最长路径全是红黑相间),换句话说,最长路径长度不会大于最短路径的2倍。红黑树的查找、添加、删除操作的时间复杂度都是O(lgn),能很大程度解决一般二叉树极端情况下退化为链表的情况。
红黑树具有以下5条特性:
- 每个节点要么是黑色,要么是红色。
- 根节点是黑色。
- 每个叶子节点(NIL)是黑色。
- 每个红色结点的两个子结点一定都是黑色。
- 任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
3.TreeMap#get方法
查找元素:
- 从root遍历整个树;
- 如果待查找的key比当前遍历的key小,则在其左子树中查找;
- 如果待查找的key比当前遍历的key大,则在其右子树中查找;
- 如果待查找的key与当前遍历的key相等,则找到了该元素,直接返回;
3.1 流程图
3.2 源码分析
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
// 使用Comparator
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
// 使用Comparable
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)
// 如果小于0从左子树查找
p = p.left;
else if (cmp > 0)
// 如果大于0从右子树查找
p = p.right;
else
// 如果相等说明找到了直接返回
return p;
}
return null;
}
final Entry<K,V> getEntryUsingComparator(Object key) {
@SuppressWarnings("unchecked")
K k = (K) key;
Comparator<? super K> cpr = comparator;
if (cpr != null) {
Entry<K,V> p = root;
while (p != null) {
int cmp = cpr.compare(k, p.key);
if (cmp < 0)
// 如果小于0从左子树查找
p = p.left;
else if (cmp > 0)
// 如果大于0从右子树查找
p = p.right;
else
// 如果相等说明找到了直接返回
return p;
}
}
return null;
}
4.TreeMap#put方法
插入元素,如果元素在树中存在,则替换value;如果元素不存在,则插入到对应的位置,再自平衡。
4.1 流程图
4.2 插入情景
4.3 JDK源码分析
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
// 根节点为空,直接插入节点为根节点,默认为黑节点
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K