版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)
TreeMap的插入操作就是按照Key的对比往下遍历,大于比较节点往右走,小于比较节点往左走,先按照二叉查找树的特性进行操作,无须关心节点颜色与树的平衡,后续会重新着色和旋转。
如果一个新节点在插入时能够运行到 fixAfterInsertion()进行着色和旋转。
说明:
-
新节点加入之前是非空树
-
新节点的Key与任何节点都不相同
fixAfterInsertion()源码:
理解下面源码需要知道几个前提:
节点的父亲是红色,叔叔是红色,则重新着色
节点的父亲是红色,叔叔是黑色,而新节点是父亲的左节点,进行右旋
节点的父亲是红色,叔叔是黑色,而新节点是父亲的右节点,进行左旋。
private void fixAfterInsertion(Entry<K, V> x) {
x.color = RED;
while (x != null && x != root && x.parent.color == RED) {
// 父节点位于爷爷节点的左子节点
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
// 需要看右叔的脸色
Entry<K, V> y = rightOf(parentOf(parentOf(x)));
// 右叔是红色,需要重新着色
if (colorOf(y) == RED) {
// 父亲置为黑色
setColor(parentOf(x), BLACK);
// 右叔置为黑色
setColor(y, BLACK);
// 爷爷置为红色
setColor(parentOf(parentOf(x)), RED);
// 爷爷成为新的节点,继续下一轮循环
x = parentOf(parentOf(x));
} else {
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
rotateLeft(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
} else {
// 父节点位于爷爷的右子节点,需要看左叔的脸色
Entry<K, V> y = leftOf(parentOf(parentOf(x)));
// 判断是否重新着色
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
// 如果左叔是黑色的, 则需要做左旋
if (x == leftOf(parentOf(x))) {
x = parentOf(x);
rotateRight(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = BLACK;
}
关于节点的相关方法:
public static <K, V> Entry<K, V> parentOf(Entry<K, V> p) {
return (p == null ? null : p.parent);
}
public static <K, V> Entry<K, V> leftOf(Entry<K, V> p) {
return (p == null ? null : p.left);
}
public static <K, V> Entry<K, V> rightOf(Entry<K, V> p) {
return (p == null ? null : p.right);
}
// 返回某个节点的颜色,如果该节点为null,默认该节点是黑色,红黑树特性
public static <K, V> boolean colorOf(Entry<K, V> p) {
return p == null ? BLACK : p.color;
}
// 如果给定节点不为空,则设置指定节点的颜色
public static <K, V> void setColor(Entry<K, V> p, boolean c) {
if (p != null) {
p.color = c;
}
}
TreeMap的几个属性字段:
private final Comparator<? super K> comparator; // 决定key顺序的比较器
private transient Entry<K,V> root; // 根节点的对象
/**
* The number of entries in the tree
*/
private transient int size = 0;
/**
* The number of structural modifications to the tree.
*/
private transient int modCount = 0;
描绘红黑树节点的静态类
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;
boolean color = BLACK;
/**
* Make a new cell with given key, value, and parent, and with
* {@code null} child links, and BLACK color.
*/
Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
}
/**
* Returns the key.
*
* @return the key
*/
public K getKey() {
return key;
}
/**
* Returns the value associated with the key.
*
* @return the value associated with the key
*/
public V getValue() {
return value;
}
/**
* Replaces the value currently associated with the key with the given
* value.
*
* @return the value associated with the key before this method was
* called
*/
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
}
public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash;
}
public String toString() {
return key + "=" + value;
}
}