You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
//可以构造Tree的时候自定义构造器Comparator,也可以让key实现Comparable接口,也就是说key一定
//是可排序的
private final Comparator<? super K> comparator;
//树节点
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
//左孩子
Entry<K,V> left;
//右孩子
Entry<K,V> right;
//父亲
Entry<K,V> parent;
//黑色为true,红色为false
boolean color = BLACK;
}
}
3.查找
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
//使用Comparator比较器
if (comparator != null)
return getEntryUsingComparator(key);
//不支持key为null的场景
if (key == null)
throw new NullPointerException();
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;
}
//使用Comparator比较器,逻辑跟上面是一样的
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)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
}
return null;
}
1.准备工作
TreeMap的实现是红黑树,所以请先熟悉本人原创的红黑树原理一文:diaosichengxuyuan/DataStructureAlgorithm#4
本文中源码的解释就是基于此文中的图示,方便大家理解。另外,TreeSet可以实现一致性哈希算法
2.基础数据模型
3.查找
4.插入
首先我们看下左旋转和右旋转的代码
一些其他的方法,大体看一下
插入的逻辑
上面代码中我觉得有两点体现了工匠精神:1.循环使用的是do while而不是while,因为已经判断了t!=null,所以do while的第一次肯定是成立的,比while循环减少一次判断。2.使用cmp在迭代过程中直接确定了e是parent的左孩子还是右孩子,不用在添加的时候多一次计算。
其实红黑树插入过程与二叉排序树的插入过程一样,不同点在于插入完成后需要执行调整方法fixAfterInsertion,下面看下调整过程:
5.删除
删除后的调整过程
其实还有一点非常有意思,deleteEntry方法中当p是叶子节点时,是先调用fixAfterDeletion调整,然后再将p删除,而叶子节点删除时,是先将p删除,用replacement替换p,然后再调整。想一想为什么呢?其实非叶子节点replacement替换p之后,replacement的上下引用关系跟p原来是一模一样的,fixAfterDeletion方法逻辑正确,而叶子节点如果先删除,那它的replacement可就是null了,fixAfterDeletion就没法用了。至于到底应该先删再调整还是先调整再删,其实都可以,只是代码就不能这么写了。
作者原创,转载请注明出处,违法必究!
The text was updated successfully, but these errors were encountered: