TreeMap
属性
//比较器,用于比较判断存放数据与已存在节点的大小比较
private final Comparator<? super K> comparator;
//根节点(将存入的k-v对封装成Entry节点)
private transient Entry<K,V> root;
//已存入节点的数量
private transient int size = 0;
//操作的次数,将每次对节点的操作会进行自增,用于failfast(快速失败)的机制
private transient int modCount = 0;
//红色
private static final boolean RED = false;
//黑色
private static final boolean BLACK = true;
构造方法
//无参构造 将其中的构造器置为null
public TreeMap() {
comparator = null;
}
//将自己的比较器设置给TreeMap
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
Put方法
public V put(K key, V value) {
//将根节点赋值给局部变量t
Entry<K,V> t = root;
//当第一次存储时根节点root为null
if (t == null) {
//比较存储的key是否为null,如果为null底层会报NPE异常
compare(key, key); // type (and possibly null) check
//将传入的K-V对封装成一个Entry节点并赋值给root属性
root = new Entry<>(key, value, null);
//因为是只有第一次存储数据会进入所以size直接设置成了1
size = 1;
//修改次数直接进行自增
modCount++;
return null;
}
//用于存储比较器比较后返回的int值
int cmp;
//申明父节点的零时变量
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
//当比较器不为空时
if (cpr != null) {
//下面的循环是为了循环查找到传入的K-V对因该处于树的什么位置
do {
//第一次进入循环时,t为上面的根节点
parent = t;
//将根节点和传入的key进行比较
cmp = cpr.compare(key, t.key);
//如果传入的key比根节点小,则将根节点的左子节点赋值给零时变量t
if (cmp < 0)
t = t.left;
//相反如果传入的key比t节点要大则将t的右子节点赋值给t变量
else if (cmp > 0)
t = t.right;
else
//如果传入的key和t变量相等那么直接进行value值的替换就可以了
return t.setValue(value);
} while (t != null);
}
else {//代表比较器为null
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
//会使用出入的key的比较器
Comparable<? super K> k = (Comparable<? super K>) key;
//下面的循环和上面的循环一样也是为了找到传入的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);
}
//将传入的key-value和上面个的parent父节点封装成一个Entry节点
Entry<K,V> e = new Entry<>(key, value, parent);
//如果比较的结果小于0则新的Entry对象会存放在父节点的左子节点
if (cmp < 0)
parent.left = e;
else
//如果比较的结果大于0则新的Entry对象会存放在父节点的右子节点
parent.right = e;
//将以存储的数据进行颜色的变更和旋转来达到红黑树的自平衡效果
fixAfterInsertion(e);
//树中的元素个数会进行自增
size++;
//变动次数会进行新增
modCount++;
return null;
}
红黑树新增节点的几种情况:
- 当root节点不存在时,直接新增并且将root节点设置为黑色
- 插入节点的父节点为黑色时,则直接插入并将自身设置为红色节点
- 插入节点的父节点为红色时:
3.1 叔叔节点存在且为红色时,那么将父节点和叔叔节点变成黑色节点,然后将祖父节点变成红色,然后将祖父节点赋值给插入节点,递归此步骤进行颜色的变更。
3.2叔叔节点不存在或者为黑色时:
3.2.1 父节点时祖父节点的左节点时:
3.2.1.1 插入节点是父节点的左子节点,将父节点设置为黑色,将祖父节点设置为红色。
3.2.1.2插入节点是父节点的右子节点,将父节点进行左旋,然后将父节点设置为插入节点执行3.2.1.1的操作。
3.2.2 父节点是祖父节点的右子节点:
3.2.2.1插入节点为父节点的右子节点。则将父节点设置为黑色将祖父节点设置为红色,对祖父节点进行左旋
3.2.2.2插入节点为父节点的左子节点,则将父节点进行右旋,将父节点设置为插入节点然后执行3.2.2.1的操作
fixAfterInsertion方法
private void fixAfterInsertion(Entry<K,V> x) {
//将新增的节点设置为红色节点
x.color = RED;
//当新增节点不为空并且新增节点不是root节点并且新增节点的父节点是红色节点时
while (x != null && x != root && x.parent.color == RED) {
//如果新增节点的父节点是祖父节点的左子节点
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
//将祖父节点的右子节点即为叔叔节点赋值给局部变量y
Entry<K,V> y = rightOf(parentOf(parentOf(x)));
//如果叔叔节点为红色,则满足3.1的插入规则
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变量
x = parentOf(x);
//进行左旋
rotateLeft(x);
}
//将父节点设置为黑色
setColor(parentOf(x), BLACK);
//将祖父节点设置为红色
setColor(parentOf(parentOf(x)), RED);
//将祖父节点进行右旋
rotateRight(parentOf(parentOf(x)));
}
} else {
//将祖父节点赋值给变量y
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
x = parentOf(parentOf(x));
} else {
//判断父节点的左节点是否存在
if (x == leftOf(parentOf(x))) {
//父节点赋值给x变量
x = parentOf(x);
//父节点进行右旋
rotateRight(x);
}
//将父节点设置为黑色
setColor(parentOf(x), BLACK);
//将祖父节点设置为红色
setColor(parentOf(parentOf(x)), RED);
//将祖父节点进行左旋
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = BLACK;
}