返回
红黑树的正确用法,一次性掌握
见解分享
2023-10-24 08:46:16
1. 红黑树简介
红黑树 (Red-Black Tree)是计算机科学中一种自平衡二叉查找树,它是对二叉查找树的一种改进,具有较好的搜索性能。红黑树与AVL树都是二叉排序树,但红黑树比AVL树具有更简单的实现和更好的效率。
2. 红黑树的性质
红黑树具有以下性质:
- 每个结点要么是红色,要么是黑色。
- 根结点是黑色。
- 每个叶结点是黑色。(叶结点是指没有子结点的结点。)
- 每个结点的两个子结点都是红色的。(称为连续红色性质)
- 从根结点到叶结点的路径上的黑色结点数量相同。(称为黑高相等性质)
3. 红黑树的操作
红黑树的操作与二叉排序树的操作类似,主要包括插入、删除和查找操作。
3.1 插入操作
红黑树的插入操作可以分为以下几个步骤:
- 将新结点插入到二叉排序树中,并将其颜色设置为红色。
- 如果新结点的父结点是红色,则执行修复操作。
- 修复操作包括以下几种情况:
- 如果新结点的叔叔结点是红色,则将新结点、新结点的父结点和新结点的叔叔结点都染成黑色,并将其祖父结点染成红色。
- 如果新结点的叔叔结点是黑色,则有两种情况:
- 如果新结点是其父结点的右结点,则将新结点的父结点染成黑色,将新结点染成红色,并对其父结点进行右旋操作。
- 如果新结点是其父结点的左结点,则将新结点的父结点染成黑色,将新结点染成红色,并对其父结点进行左旋操作。
3.2 删除操作
红黑树的删除操作可以分为以下几个步骤:
- 如果要删除的结点是红色,则将其直接删除。
- 如果要删除的结点是黑色,则将其转换为红色,并对其子树进行重新着色。
- 重新着色操作包括以下几种情况:
- 如果要删除的结点的两个子结点都是黑色,则将其兄弟结点染成红色,并将其父结点染成黑色。
- 如果要删除的结点的兄弟结点是红色,则将要删除的结点和其兄弟结点都染成黑色,并将其父结点染成红色。
- 如果要删除的结点的兄弟结点是黑色,且其兄弟结点的两个子结点都是黑色,则将其兄弟结点的右结点染成红色,并对其兄弟结点进行左旋操作。
- 如果要删除的结点的兄弟结点是黑色,且其兄弟结点的左子结点是红色,则将要删除的结点和其兄弟结点的左子结点都染成黑色,并将其兄弟结点染成红色,并对其兄弟结点进行右旋操作。
3.3 查找操作
红黑树的查找操作与二叉排序树的查找操作类似,通过不断与根结点比较,找到要查找的结点。
4. 红黑树的应用
红黑树由于其良好的搜索性能,被广泛应用于各种需要高效搜索的数据结构中,例如:
- 数据库索引
- 文件系统索引
- 网络路由表
- 编译器中的符号表
5. 红黑树的示例代码
以下是一个简单的红黑树的示例代码:
public class RedBlackTree {
private static final boolean RED = true;
private static final boolean BLACK = false;
private Node root;
private class Node {
int key;
Node left;
Node right;
boolean color;
public Node(int key) {
this.key = key;
this.color = RED;
}
}
public void insert(int key) {
Node node = new Node(key);
insert(node);
}
private void insert(Node node) {
root = insert(node, root);
root.color = BLACK;
}
private Node insert(Node node, Node parent) {
if (parent == null) {
return node;
}
if (node.key < parent.key) {
parent.left = insert(node, parent.left);
} else {
parent.right = insert(node, parent.right);
}
if (isRed(parent.right) && !isRed(parent.left)) {
parent = leftRotate(parent);
}
if (isRed(parent.left) && isRed(parent.left.left)) {
parent = rightRotate(parent);
}
if (isRed(parent.left) && isRed(parent.right)) {
flipColors(parent);
}
return parent;
}
public Node search(int key) {
return search(key, root);
}
private Node search(int key, Node node) {
if (node == null) {
return null;
}
if (key == node.key) {
return node;
} else if (key < node.key) {
return search(key, node.left);
} else {
return search(key, node.right);
}
}
public void delete(int key) {
delete(key, root);
}
private void delete(int key, Node node) {
if (node == null) {
return;
}
if (key < node.key) {
delete(key, node.left);
} else if (key > node.key) {
delete(key, node.right);
} else {
if (node.left == null) {
transplant(node, node.right);
} else if (node.right == null) {
transplant(node, node.left);
} else {
Node successor = findMin(node.right);
node.key = successor.key;
delete(successor.key, node.right);
}
}
if (root != null) {
root.color = BLACK;
}
}
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;
}
if (v != null) {
v.parent = u.parent;
}
}
private Node findMin(Node node) {
if (node == null) {
return null;
}
while (node.left != null) {
node = node.left;
}
return node;
}
private boolean isRed(Node node) {
return node != null && node.color == RED;
}
private Node leftRotate(Node node) {
Node right = node.right;
node.right = right.left;
if (right.left != null) {
right.left.parent = node;
}
right.parent = node.parent;
if (node.parent == null) {
root = right;
} else if (node == node.parent.left) {
node.parent.left = right;
} else {
node.parent.right = right;
}
right.left = node;
node.parent = right;
return right;
}
private Node rightRotate(Node node) {
Node left = node.left;
node.left = left.right;
if (left.right != null) {
left.right.parent = node;
}
left.parent = node.parent;
if (node.parent ==