java集合-TreeMap(红黑树)五
红黑树的定义
- 根节点与叶节点都是黑色节点(注意:叶节点为Null节点哦,普通二叉树里面叶子节点是左右节点为null的节点为叶子节点,而红黑树是null节点为叶子节点)
- 不能有连续两个红色节点
- 任意节点到叶子节点所经过的黑色节点数量是相同的(比如:根节点不管走左右节点到达null节点所经过的黑色节点数都是一样的)。
红黑树最难的就是:添加和删除了。
TreeMap的添加后的修复代码
//父节点是红色
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)));
}
}
}
尝试找到一些规律:
父子同时为红色;
父在右,叔父也为红色,则
1.将父节点变为黑色
2.叔父节点变为黑色
3.祖父节点变为红色
父在右,叔父为黑色,则
子在左则先:父右旋转,旋转后子变父,父变子。
子在右不变。
1.将父节点着色为黑色;(这里的父节点已经是转换后的父节点了,不是第一步的父节点了)。
2.父节点的父节点着色为红色;
3.将祖父节点左旋转。
父在左,叔父也为红色,则:
1.父节点着色为黑色。
2.叔父节点着色黑色。
3.祖父节点着色为红色。
父在左,叔父为黑色,则
子在右:父左旋转,旋转后子变父,父变子。
子在左不变。
1.将父节点着色为黑色;(这里的父节点已经是转换后的父节点了,不是第一步的父节点了)。
2.父节点的父节点着色为红色;
3.将祖父节点右旋转。
删除时的修复树代码
private void fixAfterDeletion(Entry<K,V> x) {
//x是否是黑色
while (x != root && colorOf(x) == BLACK) {
//是否是左节点
if (x == leftOf(parentOf(x))) {
Entry<K,V> sib = rightOf(parentOf(x));
//x的兄弟节点是否是红色的,兄弟着色为黑色,父节点着色为红色,父节点左旋转。
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));//左旋转
sib = rightOf(parentOf(x));
}
//兄弟节点的左右节点是否是黑色的,如果是则把兄弟节点着色为红色。
if (colorOf(leftOf(sib)) == BLACK &&
colorOf(rightOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
//兄弟节点的右节点是否是黑色的,是则右旋转一次
if (colorOf(rightOf(sib)) == BLACK) {
setColor(leftOf(sib), BLACK);
setColor(sib, RED);
rotateRight(sib);//右旋转
sib = rightOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));//兄弟节点着色为父节点的颜色
setColor(parentOf(x), BLACK);//x父节点着色为黑色
setColor(rightOf(sib), BLACK);//兄弟节点的右节点着色为黑色
rotateLeft(parentOf(x));//x父节点左旋转
x = root;
}
} else { // symmetric
Entry<K,V> sib = leftOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
}
if (colorOf(rightOf(sib)) == BLACK &&
colorOf(leftOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(leftOf(sib)) == BLACK) {
setColor(rightOf(sib), BLACK);
setColor(sib, RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(leftOf(sib), BLACK);
rotateRight(parentOf(x));
x = root;
}
}
}
setColor(x, BLACK);
}
总结:
添加时,父节点为红色才需要调整;删除时,删除的是黑色节点才需要调整。
添加时,调整与叔父节点相关;删除时,调整与兄弟节点相关。
参考
http://www.importnew.com/24930.html 红黑树添加
http://www.importnew.com/25125.html 红黑树的删除。
https://tech.meituan.com/redblack-tree.html
http://www.cs.usfca.edu/~galles/visualization/RedBlack.html红黑树动态演示地址