TreeMap通过put()和deleteEntry()实现红黑树的增加和删除节点操作
新增节点前提:
- 需要调整的节点总是红色的 如果插入新节点的父节点是黑色的,无须调整
- 如果插入新节点的父节点是红色的,因为红黑树规定不能出现相邻的两个红色节点,所以 进入循环判断,或重新着色,或左右旋转,最终达到红黑树的约束条件
退出条件如下:
- while (x != null && x != root && x.parent.color == RED){...}
- TreeMap的插入: TreeMap的插入操作是按照Key的对比往下遍历,大于比较节点值的向右走,小于比较节点的值 往左走,
- 先按照二叉查找树的特性进行操作,无须关心节点的颜色与树的平衡,后续会重新着色和旋转
public V put(K key, V value) {
// t 表示当前节点
TreeMap.Entry<K, V> t = root;
// 如果当前节点为null,即是空树,新增的KV形成的节点就是根节点
if (t == null) {
compare(key, key); // type (and possibly null) check
// 根节点赋值,根节点没有父节点
root = new TreeMap.Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
TreeMap.Entry<K, V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
// 比较器不为空
if (cpr != null) {
// 循环的目标: 根据参数Key与当前节点的key进行不断的对比
do {
// 从根节点开始比较
parent = t;
// 比较输入的参数key和当前节点的key的大小
cmp = cpr.compare(key, t.key);
// 参数的key更小,向左走
if (cmp < 0)
t = t.left;
// 参数的key更大,向右走
else if (cmp > 0)
t = t.right;
// 如果相等,会残忍地覆盖当前节点的value,并返回更新的值
else
return t.setValue(value);
} while (t != null);
}
// 在没有比较器的情况下,调用自然排序的Comparable比较
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
// 创建Entry对象
TreeMap.Entry<K, V> e = new TreeMap.Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}