红黑树是一个中和二叉平衡查找树的树
1.红黑树性质
1.每个结点要么是红的要么是黑的。
2.根结点是黑的。
3.每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。
4.如果一个结点是红的,那么它的两个儿子都是黑的。(不能有两个红色节点相连)
5.对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。
推论:如果一个节点存在黑子节点,那么该结点肯定有两个子节点。
2.红黑树平衡
左旋、右旋、变色
左旋:旋上去的顶点的左子树,变为旋下去顶点的右子树
右旋:旋上去的顶点的右子树,变为旋下去顶点的左子树
3.红黑树查找
和二叉搜索树一样
4.插入
- 查找到插入的位置
- 插入后自平衡
插入的节点必须是红色节点
1.插入21结点 没破坏平衡
2、节点的key已存在,则直接覆盖掉值
3、插入节点的父节点为黑节点,直接插入不影响平衡![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/c2bf917f364df689e68013fed9a7378b.png)
4、插入节点父节点为红色
4.1叔叔节点存在且为红节点
4.2叔叔节点不存在或为黑节点,且插入节点的父亲节点是祖父节点的左子节点
4.2.1 插入节点为其父节点的左子节点
4.2.2 插入节点为其父节点的右子节点
4.3 反方向
4.3.1 插入节点为其父节点的右子节点
4.3.2 插入节点为其父节点的左子节点
例子:
总结:
红黑树插入操作
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
TreeNode<K,V> x) {
//新节点默认为红色
x.red = true;
//xp表示为x的父节点,xpp表示x的祖父节点,xpp1表示xpp的左孩子节点,xppr表示xpp的右孩子节点
for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
//如果x没有父节点,则表示x是第一个节点,即根节点,根节点是黑色
if ((xp = x.parent) == null) {
x.red = false;
return x;
}
//如果父节点不是红色(就是黑色,或者x没有祖父节点,则x是第二层节点,父节点是根节点,无需操作。)
else if (!xp.red || (xpp = xp.parent) == null)
return root;
//如果父节点为红色
//如果x的父节点是祖父节点的左孩子
if (xp == (xppl = xpp.left)) {
//判断叔叔节点是不是红色的,红色就父节点叔叔节点变黑,祖父变红,还可能需要递归调整,接下来就调整x的祖父节点
if ((xppr = xpp.right) != null && xppr.red) {
xppr.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
//没有叔叔节点和有叔叔是黑色的情况。。
else {
if (x == xp.right) {
root = rotateLeft(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateRight(root, xpp);
}
}
}
}
else {
if (xppl != null && xppl.red) {
xppl.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
else {
if (x == xp.left) {
root = rotateRight(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateLeft(root, xpp);
}
}
}
}
}
}