背景
定义
(左根右)前提:二叉搜索树(左 < 根 < 右)
(根叶黑)根和叶子(NULL)都是黑色
(不红红)不存在连续的两个红色节点
(黑路同)任一节点到叶所有路径黑节点数量相同
性质:最长路径不超过最短路径的两倍
最长路径:一定是一黑一红一黑…一黑;最短路径顶多一黑一黑…一黑
运用:红黑树的运用比AVL树运用更广泛。HashMap、epoll…
插入
插入节点默认为红色。且只可能违反根叶黑或者不红红。
插入节点红黑树被破坏了存在三种情况:
- 插入节点是根节点(破坏了根叶黑) ——> 直接变黑
- 插入节点的叔叔是红色(破坏了不红红) ——> 叔父爷变色,爷爷变插入节点
- 插入节点的叔叔是黑色(破坏了不红红) ——> (LL,RR,LR,RL)旋转,然后变色
构建
17 18 23 34 27 15 9 6 8 5 25
删除(难点)
AVL树删除三种场景:
- 没有孩子——直接删除
- 只有左子树/只有有右子树——直接代替
- 左右子树都有——直接后继(或前驱)代替值,然后删除(转换成前两种情况)


双黑节点:所有经过它的路径都会少一个黑节点。
LL型
变色(r变s,s变p,p变黑)
右旋
双黑变单黑
p 7(黑)
/ \
s 5(黑) 双黑 d
/ \
r 2(黑) 6(红)RR型
变色(r变s,s变p,p变黑)
左旋
双黑变单黑
p 5(黑)
/ \
d 双黑 7 (黑) s
\
12(红) rLR型
变色(r变p,p变黑)
左旋左孩子,然后右旋
双黑变单黑
p 7(黑)
/ \
s 5(黑) 双黑 d
\
6(红) rRL型
变色(r变p,p变黑)
右旋右孩子,然后左旋
双黑变单黑
p 6(黑)
/ \
d 双黑 12 (黑) s
/
8(红) r红黑树删除案例
依次删除 13 37 27 17 34 9 10 23
代码实现(deepseek)
public class RBTree {
private static final boolean RED = true;
private static final boolean BLACK = false;
class Node {
int key;
Node left, right, parent;
boolean color;
Node(int key) {
this.key = key;
this.color = RED; // 新节点默认为红色
this.left = this.right = this.parent = null;
}
}
private Node root;
private final Node NIL; // 哨兵节点,代表空节点
public RBTree() {
NIL = new Node(-1);
NIL.color = BLACK;
root = NIL;
}
// 插入操作
public void insert(int key) {
Node newNode = new Node(key);
newNode.left = NIL;
newNode.right = NIL;
Node parent = null;
Node current = root;
// 标准BST插入
while (current != NIL) {
parent = current;
if (key < current.key) {
current = current.left;
} else if (key > current.key) {
current = current.right;
} else {
return; // 重复键
}
}
newNode.parent = parent;
if (parent == null) {
root = newNode;
} else if (key < parent.key) {
parent.left = newNode;
} else {
parent.right = newNode;
}
// 如果新节点是根节点,直接染黑
if (newNode.parent == null) {
newNode.color = BLACK;
return;
}
// 如果祖父节点不存在,不需要修复
if (newNode.parent.parent == null) {
return;
}
// 修复红黑树性质
fixInsert(newNode);
}
// 插入后修复
private void fixInsert(Node node) {
Node parent = node.parent;
while (parent != null && parent.color == RED) {
Node grandparent = parent.parent;
if (parent == grandparent.left) {
Node uncle = grandparent.right;
// 情况1:叔叔节点是红色
if (uncle.color == RED) {
parent.color = BLACK;
uncle.color = BLACK;
grandparent.color = RED;
node = grandparent;
parent = node.parent;
} else {
// 情况2:节点是父节点的右孩子(LR情况)
if (node == parent.right) {
node = parent;
leftRotate(node);
parent = node.parent;
}
// 情况3:节点是父节点的左孩子(LL情况)
parent.color = BLACK;
grandparent.color = RED;
rightRotate(grandparent);
}
} else {
// 对称情况:父节点是祖父节点的右孩子
Node uncle = grandparent.left;
// 情况1:叔叔节点是红色
if (uncle.color == RED) {
parent.color = BLACK;
uncle.color = BLACK;
grandparent.color = RED;
node = grandparent;
parent = node.parent;
} else {
// 情况2:节点是父节点的左孩子(RL情况)
if (node == parent.left) {
node = parent;
rightRotate(node);
parent = node.parent;
}
// 情况3:节点是父节点的右孩子(RR情况)
parent.color = BLACK;
grandparent.color = RED;
leftRotate(grandparent);
}
}
if (node == root) {
break;
}
}
root.color = BLACK; // 确保根节点始终为黑色
}
// 左旋
private void leftRotate(Node x) {
Node y = x.right;
x.right = y.left;
if (y.left != NIL) {
y.left.parent = x;
}
y.parent = x.parent;
if (x.parent == null) {
root = y;
} else if (x == x.parent.left) {
x.parent.left = y;
} else {
x.parent.right = y;
}
y.left = x;
x.parent = y;
}
// 右旋
private void rightRotate(Node y) {
Node x = y.left;
y.left = x.right;
if (x.right != NIL) {
x.right.parent = y;
}
x.parent = y.parent;
if (y.parent == null) {
root = x;
} else if (y == y.parent.right) {
y.parent.right = x;
} else {
y.parent.left = x;
}
x.right = y;
y.parent = x;
}
// 删除操作
public void delete(int key) {
deleteNode(root, key);
}
private void deleteNode(Node node, int key) {
Node z = NIL;
Node x, y;
// 查找要删除的节点
while (node != NIL) {
if (node.key == key) {
z = node;
break;
} else if (key < node.key) {
node = node.left;
} else {
node = node.right;
}
}
if (z == NIL) {
return; // 节点不存在
}
y = z;
boolean yOriginalColor = y.color;
if (z.left == NIL) {
x = z.right;
transplant(z, z.right);
} else if (z.right == NIL) {
x = z.left;
transplant(z, z.left);
} else {
y = minimum(z.right);
yOriginalColor = y.color;
x = y.right;
if (y.parent == z) {
x.parent = y;
} else {
transplant(y, y.right);
y.right = z.right;
y.right.parent = y;
}
transplant(z, y);
y.left = z.left;
y.left.parent = y;
y.color = z.color;
}
if (yOriginalColor == BLACK) {
fixDelete(x);
}
}
// 节点替换
private void transplant(Node u, Node v) {
if (u.parent == null) {
root = v;
} else if (u == u.parent.left) {
u.parent.left = v;
} else {
u.parent.right = v;
}
v.parent = u.parent;
}
// 查找最小值节点
private Node minimum(Node node) {
while (node.left != NIL) {
node = node.left;
}
return node;
}
// 删除后修复
private void fixDelete(Node x) {
while (x != root && x.color == BLACK) {
if (x == x.parent.left) {
Node w = x.parent.right;
// 情况1:兄弟节点是红色
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
leftRotate(x.parent);
w = x.parent.right;
}
// 情况2:兄弟节点的两个子节点都是黑色
if (w.left.color == BLACK && w.right.color == BLACK) {
w.color = RED;
x = x.parent;
} else {
// 情况3:兄弟节点的右子节点是黑色,左子节点是红色
if (w.right.color == BLACK) {
w.left.color = BLACK;
w.color = RED;
rightRotate(w);
w = x.parent.right;
}
// 情况4:兄弟节点的右子节点是红色
w.color = x.parent.color;
x.parent.color = BLACK;
w.right.color = BLACK;
leftRotate(x.parent);
x = root;
}
} else {
// 对称情况
Node w = x.parent.left;
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
rightRotate(x.parent);
w = x.parent.left;
}
if (w.right.color == BLACK && w.left.color == BLACK) {
w.color = RED;
x = x.parent;
} else {
if (w.left.color == BLACK) {
w.right.color = BLACK;
w.color = RED;
leftRotate(w);
w = x.parent.left;
}
w.color = x.parent.color;
x.parent.color = BLACK;
w.left.color = BLACK;
rightRotate(x.parent);
x = root;
}
}
}
x.color = BLACK;
}
// 中序遍历
public void inOrder() {
inOrder(root);
System.out.println();
}
private void inOrder(Node node) {
if (node != NIL) {
inOrder(node.left);
System.out.print(node.key + "(" + (node.color == RED ? "R" : "B") + ") ");
inOrder(node.right);
}
}
// 测试代码
public static void main(String[] args) {
RBTree tree = new RBTree();
int[] values = {7, 3, 18, 10, 22, 8, 11, 26, 2, 6, 13};
System.out.println("插入顺序: " + java.util.Arrays.toString(values));
for (int value : values) {
tree.insert(value);
}
System.out.println("中序遍历:");
tree.inOrder();
System.out.println("删除节点: 18");
tree.delete(18);
System.out.println("删除后的中序遍历:");
tree.inOrder();
}
}运行结果:
插入顺序: [7, 3, 18, 10, 22, 8, 11, 26, 2, 6, 13]
中序遍历:
2(R) 3(B) 6(R) 7(R) 8(B) 10(B) 11(B) 13(R) 18(R) 22(B) 26(R)
删除节点: 18
删除后的中序遍历:
2(R) 3(B) 6(R) 7(R) 8(B) 10(B) 11(B) 13(R) 22(R) 26(B)参考
















