如何在一棵红黑树中插入一个节点
以普通的二叉搜索树的方式将新节点插入到树中。将新插入的节点标记为红色。根据红黑树的规则进行修复,使树重新成为红黑树
-
将新插入的节点标记为红色。
-
如果新插入的节点是根节点,将其颜色修正为黑色,即满足红黑树的性质2。
-
如果新插入的节点的父节点是黑色,不需要进行修复,树仍然是红黑树。
-
如果新插入的节点的父节点是红色,需要进行修复。
a. 如果新插入的节点的叔叔节点是红色,表示父节点和叔叔节点都是红色,违反了红黑树的性质4。此时,将父节点和叔叔节点都改为黑色,将祖父节点改为红色,并以祖父节点为当前节点进行修复。
b. 如果新插入的节点的叔叔节点是黑色或不存在,表示父节点是红色,叔叔节点是黑色或不存在,需要进行旋转操作来修复。
i. 如果新插入的节点是其父节点的右子节点,并且父节点是其祖父节点的左子节点,此时需要进行左旋操作。即以父节点为支点进行左旋,将父节点变为当前节点,并以当前节点进行修复。
ii. 如果新插入的节点是其父节点的左子节点,并且父节点是其祖父节点的左子节点,此时需要进行右旋操作。即以祖父节点为支点进行右旋,将祖父节点变为当前节点,并以当前节点进行修复。
iii. 如果新插入的节点是其父节点的左子节点,并且父节点是其祖父节点的右子节点,此时需要进行先右旋后左旋的操作。即以父节点为支点进行右旋,将父节点变为当前节点,再以当前节点进行左旋,并将祖父节点变为当前节点进行修复。 iv. 如果新插入的节点是其父节点的右子节点,并且父节点是其祖父节点的右子节点,此时需要进行先左旋后右旋的操作。即以祖父节点为支点进行左旋,将祖父节点变为当前节点,再以当前节点进行右旋,并将祖父节点变为当前节点进行修复。 -
重复步骤4,直到修复完成。
// 定义红黑树节点颜色,RED为红色,BLACK为黑色
enum Color {
RED,
BLACK
}
// 定义红黑树节点类
class Node {
int val; // 节点值
Node left; // 左子节点
Node right; // 右子节点
Node parent; // 父节点
Color color; // 节点颜色
// 构造函数
public Node(int val) {
this.val = val;
this.color = Color.RED; // 默认新插入节点为红色
}
}
// 定义红黑树类
class RedBlackTree {
private Node root; // 根节点
// 构造函数
public RedBlackTree() {
this.root = null;
}
// 插入节点
public void insert(int val) {
Node newNode = new Node(val); // 新建待插入节点
if (root == null) { // 如果根节点为空,将待插入节点设为根节点,颜色为黑色
root = newNode;
newNode.color = Color.BLACK;
} else {
Node current = root; // 定义当前节点
Node parent = null; // 定义当前节点的父节点
while (true) {
parent = current;
if (val < current.val) { // 如果待插入值小于当前节点值,向左子树查找
current = current.left;
if (current == null) { // 如果左子节点为空,将待插入节点设为左子节点
parent.left = newNode;
newNode.color = Color.RED; // 新节点默认为红色
newNode = parent.left;
break;
}
} else { // 如果待插入值大于或等于当前节点值,向右子树查找
current = current.right;
if (current == null) { // 如果右子节点为空,将待插入节点设为右子节点
parent.right = newNode;
newNode.color = Color.RED; // 新节点默认为红色
newNode = parent.right;
break;
}
}
}
// 调整红黑树的平衡
fixUp(newNode);
}
}
// 调整红黑树的平衡
// 调整红黑树的平衡
private void fixUp(Node newNode) {
while (newNode != root && newNode.color == Color.RED && newNode.parent.color == Color.RED) {
// 如果当前节点的父节点是祖父节点的左子节点
if (newNode.parent == newNode.parent.parent.left) {
Node uncle = newNode.parent.parent.right; // 定义叔节点
// 如果叔节点是红色,将当前节点、父节点、叔节点都设为黑色,祖父节点设为红色,然后将当前节点移动到祖父节点
if (uncle != null && uncle.color == Color.RED) {
uncle.color = Color.BLACK;
newNode.parent.color = Color.BLACK;
newNode.parent.parent.color = Color.RED;
newNode = newNode.parent.parent;
} else { // 如果叔节点是黑色
// 如果当前节点是父节点的右子节点,先将当前节点设为父节点,然后左旋
if (newNode == newNode.parent.right) {
newNode = newNode.parent;
leftRotate(newNode);
}
// 将父节点设为黑色,祖父节点设为红色,然后右旋
newNode.parent.color = Color.BLACK;
newNode.parent.parent.color = Color.RED;
rightRotate(newNode.parent.parent);
}
} else { // 如果当前节点的父节点是祖父节点的右子节点
Node uncle = newNode.parent.parent.left; // 定义叔节点
// 如果叔节点是红色,将当前节点、父节点、叔节点都设为黑色,祖父节点设为红色,然后将当前节点移动到祖父节点
if (uncle != null && uncle.color == Color.RED) {
uncle.color = Color.BLACK;
newNode.parent.color = Color.BLACK;
newNode.parent.parent.color = Color.RED;
newNode = newNode.parent.parent;
} else { // 如果叔节点是黑色
// 如果当前节点是父节点的左子节点,先将当前节点设为父节点,然后右旋
if (newNode == newNode.parent.left) {
newNode = newNode.parent;
rightRotate(newNode);
}
// 将父节点设为黑色,祖父节点设为红色,然后左旋
newNode.parent.color = Color.BLACK;
newNode.parent.parent.color = Color.RED;
leftRotate(newNode.parent.parent);
}
}
}
root.color = Color.BLACK; // 根节点始终为黑色
}
// 左旋操作
private void leftRotate(Node x) {
Node y = x.right;
x.right = y.left;
if (y.left != null) {
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 x) {
Node y = x.left;
x.left = y.right;
if (y.right != null) {
y.right.parent = x;
}
y.parent = x.parent;
if (x.parent == null) {
root = y;
} else if (x == x.parent.right) {
x.parent.right = y;
} else {
x.parent.left = y;
}
y.right = x;
x.parent = y;
}
}