红黑树(Red-Black Tree)是一种自平衡二叉搜索树,它通过确保树的每个路径上包含相同数目的黑色节点来保持树的平衡。红黑树的每个节点包含一个颜色属性,这个属性可以是红色或黑色。通过一系列旋转和重新着色操作,红黑树在插入、删除和查找操作中都能保持较好的性能,平均和最坏情况下的时间复杂度都是O(log n)。
红黑树的性质
红黑树遵循以下五条基本性质:
- 节点是红色或黑色。
- 根节点是黑色。
- 所有叶子(NIL节点,空节点)都是黑色。
- 如果一个节点是红色的,则它的两个子节点都是黑色的(也就是说在一条路径上不能出现两个连续的红色节点)。
- 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
红黑树的基本操作
红黑树的基本操作主要包括插入和删除节点,这些操作可能需要通过旋转(左旋、右旋)和重新着色来保持树的平衡。
数据结构定义
首先,我们需要定义红黑树节点的数据结构:
#include <iostream>
#include <algorithm>
enum Color { RED, BLACK };
struct RBTreeNode {
int val;
Color color;
RBTreeNode *left, *right, *parent;
RBTreeNode(int x) : val(x), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
class RedBlackTree {
private:
RBTreeNode *root;
// 旋转函数
void leftRotate(RBTreeNode* &x);
void rightRotate(RBTreeNode* &x);
// 插入和删除后的调整函数
void fixInsert(RBTreeNode* &z);
void fixDelete(RBTreeNode* &x);
// 辅助函数
RBTreeNode* minimum(RBTreeNode* node);
RBTreeNode* successor(RBTreeNode* x);
public:
RedBlackTree() : root(nullptr) {}
// 插入函数
void insert(int val);
// 删除函数
void remove(int val);
// 中序遍历
void inorderTraversal();
// 其他函数...
};
插入操作
插入操作首先像普通二叉搜索树一样进行,然后通过fixInsert
函数调整树以恢复红黑树的性质。
void RedBlackTree::insert(int val) {
RBTreeNode* z = new RBTreeNode(val);
RBTreeNode* y = nullptr;
RBTreeNode* x = root;
while (x != nullptr) {
y = x;
if (z->val < x->val)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == nullptr)
root = z;
else if (z->val < y->val)
y->left = z;
else
y->right = z;
z->left = z->right = nullptr;
z->color = RED;
fixInsert(z);
}
void RedBlackTree::fixInsert(RBTreeNode* &z) {
RBTreeNode* y;
while (z != root && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
y = z->parent->parent->right;
if (y != nullptr && y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->right) {
z = z->parent;
leftRotate(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rightRotate(z->parent->parent);
}
} else {
// 与上面类似,但是方向相反
}
}
root->color = BLACK;
}
删除操作
删除操作稍微复杂一些,因为它可能涉及多个颜色变更和旋转。
void RedBlackTree::remove(int val) {
RBTreeNode* z =删除操作的完整实现涉及到查找要删除的节点,替换该节点(如果需要),以及通过`fixDelete`函数调整树以恢复红黑树的性质。
```cpp
void RedBlackTree::remove(int val) {
RBTreeNode* z = find(val); // 假设find函数已经实现,用于查找值为val的节点
if (z == nullptr) return; // 如果未找到节点,则直接返回
RBTreeNode* y = z;
RBTreeNode* x;
Color yOriginalColor = y->color;
// 如果z有一个孩子,y指向它的孩子;否则,y指向z
if (z->left == nullptr)
x = z->right;
else if (z->right == nullptr)
x = z->left;
else {
y = minimum(z->right); // 找到z的右子树中的最小节点
yOriginalColor = y->color;
x = y->right;
if (y->parent != z) {
// 如果y不是z的直接孩子,需要进行一些指针的调整
if (y->parent->left == y)
y->parent->left = y->right;
else
y->parent->right = y->right;
y->right = z->right;
y->right->parent = y;
}
// y现在是z的右子树中的最小节点,它替代了z
if (z == root)
root = y;
else if (z->parent->left == z)
z->parent->left = y;
else
z->parent->right = y;
y->parent = z->parent;
// 将y的内容复制到z中(假设节点包含除了值以外的其他数据)
// 这里我们简化处理,只复制值
z->val = y->val;
}
// 删除节点y(此时y指向z或z的替代者)
delete y;
// 如果y是黑色的,并且它不是根节点,我们需要进行调整
if (yOriginalColor == BLACK)
fixDelete(x);
}
void RedBlackTree::fixDelete(RBTreeNode* &x) {
while (x != root && (x == nullptr || x->color == BLACK)) {
if (x == x->parent->left) {
RBTreeNode* w = x->parent->right;
if (w->color == RED) {
w->color = BLACK;
x->parent->color = RED;
leftRotate(x->parent);
w = x->parent->right;
}
if (w->left->color == BLACK && w->right->color == BLACK) {
w->color = RED;
x = x->parent;
} else {
if (w->right->color == BLACK) {
w->left->color = BLACK;
w->color = RED;
rightRotate(w);
w = x->parent->right;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->right->color = BLACK;
leftRotate(x->parent);
x = root;
}
} else {
// 与上面类似,但是方向相反
}
}
if (x != nullptr)
x->color = BLACK;
}
// 假设的find函数,用于查找值为val的节点
RBTreeNode* RedBlackTree::find(int val) {
RBTreeNode* current = root;
while (current != nullptr) {
if (val < current->val)
current = current->left;
else if (val > current->val)
current = current->right;
else
return current;
}
return nullptr;
}
// 其他函数如leftRotate, rightRotate, minimum, successor等可以根据需要实现
请注意,上面的remove
函数实现中,我采用了“复制替代”的方法来处理删除操作中的节点替换,这是为了简化说明。在实际应用中,你可能需要根据节点的具体内容和需求来调整这一部分的实现。
此外,find
函数是一个简单的二叉搜索树查找函数,用于在红黑树中查找特定值的节点。而leftRotate
, rightRotate
, minimum
, successor
等函数则是红黑树操作中常用的辅助函数,它们的实现依赖于基本的树