目录
[利用Graphviz 库](#利用Graphviz 库)
摘要
红黑树是一种自平衡的二叉搜索树,它在插入和删除节点时,通过颜色和旋转操作保持树的平衡,确保插入、删除和查找的时间复杂度都是 (O(log n))。红黑树的每个节点都有一个颜色属性,红色或黑色。通过一些规则,红黑树保持了相对平衡,使得最长路径长度不会超过最短路径长度的两倍。
基本规则
-
每个节点不是红色就是黑色。
-
根节点是黑色。
-
每个叶子节点(NIL 节点)是黑色。
-
如果一个节点是红色的,则它的两个子节点都是黑色的(从每个叶子到根的所有路径上不能有两个连续的红色节点)。
-
从任一节点到其每个叶子的所有简单路径都包含相同数量的黑色节点。
基本操作
插入操作
cpp
#include <iostream>
enum Color { RED, BLACK };
struct Node {
int data;
Color color;
Node *left, *right, *parent;
Node(int data) : data(data), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
class RedBlackTree {
public:
RedBlackTree() : root(nullptr) {}
void insert(int data) {
Node* newNode = new Node(data);
root = bstInsert(root, newNode);
fixViolation(newNode);
}
void inorder() { inorderHelper(root); }
private:
Node* root;
Node* bstInsert(Node* root, Node* node) {
if (root == nullptr) return node;
if (node->data < root->data) {
root->left = bstInsert(root->left, node);
root->left->parent = root;
} else if (node->data > root->data) {
root->right = bstInsert(root->right, node);
root->right->parent = root;
}
return root;
}
void fixViolation(Node* node) {
Node* parent = nullptr;
Node* grandParent = nullptr;
while (node != root && node->color == RED && node->parent->color == RED) {
parent = node->parent;
grandParent = parent->parent;
if (parent == grandParent->left) {
Node* uncle = grandParent->right;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
} else {
if (node == parent->right) {
rotateLeft(parent);
node = parent;
parent = node->parent;
}
rotateRight(grandParent);
std::swap(parent->color, grandParent->color);
node = parent;
}
} else {
Node* uncle = grandParent->left;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
} else {
if (node == parent->left) {
rotateRight(parent);
node = parent;
parent = node->parent;
}
rotateLeft(grandParent);
std::swap(parent->color, grandParent->color);
node = parent;
}
}
}
root->color = BLACK;
}
void rotateLeft(Node* node) {
Node* rightNode = node->right;
node->right = rightNode->left;
if (node->right != nullptr) node->right->parent = node;
rightNode->parent = node->parent;
if (node->parent == nullptr) root = rightNode;
else if (node == node->parent->left) node->parent->left = rightNode;
else node->parent->right = rightNode;
rightNode->left = node;
node->parent = rightNode;
}
void rotateRight(Node* node) {
Node* leftNode = node->left;
node->left = leftNode->right;
if (node->left != nullptr) node->left->parent = node;
leftNode->parent = node->parent;
if (node->parent == nullptr) root = leftNode;
else if (node == node->parent->left) node->parent->left = leftNode;
else node->parent->right = leftNode;
leftNode->right = node;
node->parent = leftNode;
}
void inorderHelper(Node* root) {
if (root == nullptr) return;
inorderHelper(root->left);
std::cout << root->data << " ";
inorderHelper(root->right);
}
};
int main() {
RedBlackTree tree;
tree.insert(10);
tree.insert(20);
tree.insert(30);
tree.insert(15);
std::cout << "Inorder traversal of the constructed tree is ";
tree.inorder();
std::cout << std::endl;
return 0;
}
cpp
// Output
Inorder traversal of the constructed tree is 10 15 20 30
20(B)
/ \
10(B) 30(B)
\
15(R)
插入和删除操作
cpp
#include <iostream>
#include <queue>
enum Color { RED, BLACK };
struct Node {
int data;
Color color;
Node *left, *right, *parent;
Node(int data) : data(data), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
Node* sibling() {
if (parent == nullptr) return nullptr;
return this == parent->left ? parent->right : parent->left;
}
bool hasRedChild() {
return (left != nullptr && left->color == RED) || (right != nullptr && right->color == RED);
}
};
class RedBlackTree {
public:
Node* root;
RedBlackTree() : root(nullptr) {}
void insert(int data) {
Node* newNode = new Node(data);
root = bstInsert(root, newNode);
fixViolation(newNode);
}
void deleteNode(int data) {
Node* nodeToDelete = search(root, data);
if (nodeToDelete == nullptr) return;
deleteBSTNode(nodeToDelete);
}
void inorder() { inorderHelper(root); }
void levelOrder() {
if (root == nullptr) return;
std::queue<Node*> q;
q.push(root);
while (!q.empty()) {
Node* temp = q.front();
std::cout << temp->data << " ";
q.pop();
if (temp->left != nullptr)
q.push(temp->left);
if (temp->right != nullptr)
q.push(temp->right);
}
}
private:
Node* bstInsert(Node* root, Node* node) {
if (root == nullptr) return node;
if (node->data < root->data) {
root->left = bstInsert(root->left, node);
root->left->parent = root;
} else if (node->data > root->data) {
root->right = bstInsert(root->right, node);
root->right->parent = root;
}
return root;
}
Node* search(Node* root, int data) {
if (root == nullptr || root->data == data) return root;
return data < root->data ? search(root->left, data) : search(root->right, data);
}
void deleteBSTNode(Node* node) {
Node* replacement = BSTreplace(node);
bool bothBlack = ((replacement == nullptr || replacement->color == BLACK) && (node->color == BLACK));
Node* parent = node->parent;
if (replacement == nullptr) {
if (node == root) {
root = nullptr;
} else {
if (bothBlack) {
fixDoubleBlack(node);
} else {
if (node->sibling() != nullptr) node->sibling()->color = RED;
}
if (node == node->parent->left) {
node->parent->left = nullptr;
} else {
node->parent->right = nullptr;
}
}
delete node;
return;
}
if (node->left == nullptr || node->right == nullptr) {
if (node == root) {
node->data = replacement->data;
node->left = node->right = nullptr;
delete replacement;
} else {
if (node == node->parent->left) {
parent->left = replacement;
} else {
parent->right = replacement;
}
delete node;
replacement->parent = parent;
if (bothBlack) {
fixDoubleBlack(replacement);
} else {
replacement->color = BLACK;
}
}
return;
}
std::swap(node->data, replacement->data);
deleteBSTNode(replacement);
}
Node* BSTreplace(Node* node) {
if (node->left != nullptr && node->right != nullptr) return successor(node->right);
if (node->left == nullptr && node->right == nullptr) return nullptr;
return node->left != nullptr ? node->left : node->right;
}
Node* successor(Node* node) {
Node* temp = node;
while (temp->left != nullptr) temp = temp->left;
return temp;
}
void fixViolation(Node* node) {
Node* parent = nullptr;
Node* grandParent = nullptr;
while (node != root && node->color == RED && node->parent->color == RED) {
parent = node->parent;
grandParent = parent->parent;
if (parent == grandParent->left) {
Node* uncle = grandParent->right;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
} else {
if (node == parent->right) {
rotateLeft(parent);
node = parent;
parent = node->parent;
}
rotateRight(grandParent);
std::swap(parent->color, grandParent->color);
node = parent;
}
} else {
Node* uncle = grandParent->left;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
} else {
if (node == parent->left) {
rotateRight(parent);
node = parent;
parent = node->parent;
}
rotateLeft(grandParent);
std::swap(parent->color, grandParent->color);
node = parent;
}
}
}
root->color = BLACK;
}
void fixDoubleBlack(Node* node) {
if (node == root) return;
Node* sibling = node->sibling();
Node* parent = node->parent;
if (sibling == nullptr) {
fixDoubleBlack(parent);
} else {
if (sibling->color == RED) {
parent->color = RED;
sibling->color = BLACK;
if (sibling == parent->left) {
rotateRight(parent);
} else {
rotateLeft(parent);
}
fixDoubleBlack(node);
} else {
if (sibling->hasRedChild()) {
if (sibling->left != nullptr && sibling->left->color == RED) {
if (sibling == parent->left) {
sibling->left->color = sibling->color;
sibling->color = parent->color;
rotateRight(parent);
} else {
sibling->left->color = parent->color;
rotateRight(sibling);
rotateLeft(parent);
}
} else {
if (sibling == parent->left) {
sibling->right->color = parent->color;
rotateLeft(sibling);
rotateRight(parent);
} else {
sibling->right->color = sibling->color;
sibling->color = parent->color;
rotateLeft(parent);
}
}
parent->color = BLACK;
} else {
sibling->color = RED;
if (parent->color == BLACK) {
fixDoubleBlack(parent);
} else {
parent->color = BLACK;
}
}
}
}
}
void rotateLeft(Node* node) {
Node* rightNode = node->right;
node->right = rightNode->left;
if (node->right != nullptr) node->right->parent = node;
rightNode->parent = node->parent;
if (node->parent == nullptr) root = rightNode;
else if (node == node->parent->left) node->parent->left = rightNode;
else node->parent->right = rightNode;
rightNode->left = node;
node->parent = rightNode;
}
void rotateRight(Node* node) {
Node* leftNode = node->left;
node->left = leftNode->right;
if (node->left != nullptr) node->left->parent = node;
leftNode->parent = node->parent;
if (node->parent == nullptr) root = leftNode;
else if (node == node->parent->left) node->parent->left = leftNode;
else node->parent->right = leftNode;
leftNode->right = node;
node->parent = leftNode;
}
void inorderHelper(Node* root) {
if (root == nullptr) return;
inorderHelper(root->left);
std::cout << root->data << " ";
inorderHelper(root->right);
}
};
int main() {
RedBlackTree tree;
tree.insert(10);
tree.insert(20);
tree.insert(30);
tree.insert(15);
tree.insert(25);
tree.insert(5);
std::cout << "Inorder traversal of the constructed tree is ";
tree.inorder();
std::cout << std::endl;
tree.deleteNode(20);
std::cout << "Inorder traversal after deleting 20 is ";
tree.inorder();
std::cout << std::endl;
std::cout << "Level order traversal of the tree is ";
tree.levelOrder();
std::cout << std::endl;
return 0;
}
cpp
// Output
Inorder traversal of the constructed tree is 5 10 15 20 25 30
Inorder traversal after deleting 20 is 5 10 15 25 30
Level order traversal of the tree is 15 10 30 5 25
15(B)
/ \
10(B) 30(B)
/ /
5(B) 25(R)
利用Graphviz 库
利用 Graphviz 库的图形化表示我们需要生成的红黑树。
cpp
#include <iostream>
#include <fstream>
#include <queue>
enum Color { RED, BLACK };
struct Node {
int data;
Color color;
Node *left, *right, *parent;
Node(int data) : data(data), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
Node* sibling() {
if (parent == nullptr) return nullptr;
return this == parent->left ? parent->right : parent->left;
}
bool hasRedChild() {
return (left != nullptr && left->color == RED) || (right != nullptr && right->color == RED);
}
};
class RedBlackTree {
public:
Node* root;
RedBlackTree() : root(nullptr) {}
void insert(int data) {
Node* newNode = new Node(data);
root = bstInsert(root, newNode);
fixViolation(newNode);
}
void deleteNode(int data) {
Node* nodeToDelete = search(root, data);
if (nodeToDelete == nullptr) return;
deleteBSTNode(nodeToDelete);
}
void inorder() { inorderHelper(root); }
void levelOrder() {
if (root == nullptr) return;
std::queue<Node*> q;
q.push(root);
while (!q.empty()) {
Node* temp = q.front();
std::cout << temp->data << " ";
q.pop();
if (temp->left != nullptr)
q.push(temp->left);
if (temp->right != nullptr)
q.push(temp->right);
}
}
void generateGraphviz(const std::string& filename) {
std::ofstream file(filename);
file << "digraph G {\n";
if (root == nullptr) {
file << "}\n";
return;
}
generateGraphvizHelper(file, root);
file << "}\n";
}
private:
Node* bstInsert(Node* root, Node* node) {
if (root == nullptr) return node;
if (node->data < root->data) {
root->left = bstInsert(root->left, node);
root->left->parent = root;
} else if (node->data > root->data) {
root->right = bstInsert(root->right, node);
root->right->parent = root;
}
return root;
}
Node* search(Node* root, int data) {
if (root == nullptr || root->data == data) return root;
return data < root->data ? search(root->left, data) : search(root->right, data);
}
void deleteBSTNode(Node* node) {
Node* replacement = BSTreplace(node);
bool bothBlack = ((replacement == nullptr || replacement->color == BLACK) && (node->color == BLACK));
Node* parent = node->parent;
if (replacement == nullptr) {
if (node == root) {
root = nullptr;
} else {
if (bothBlack) {
fixDoubleBlack(node);
} else {
if (node->sibling() != nullptr) node->sibling()->color = RED;
}
if (node == node->parent->left) {
node->parent->left = nullptr;
} else {
node->parent->right = nullptr;
}
}
delete node;
return;
}
if (node->left == nullptr || node->right == nullptr) {
if (node == root) {
node->data = replacement->data;
node->left = node->right = nullptr;
delete replacement;
} else {
if (node == node->parent->left) {
parent->left = replacement;
} else {
parent->right = replacement;
}
delete node;
replacement->parent = parent;
if (bothBlack) {
fixDoubleBlack(replacement);
} else {
replacement->color = BLACK;
}
}
return;
}
std::swap(node->data, replacement->data);
deleteBSTNode(replacement);
}
Node* BSTreplace(Node* node) {
if (node->left != nullptr && node->right != nullptr) return successor(node->right);
if (node->left == nullptr && node->right == nullptr) return nullptr;
return node->left != nullptr ? node->left : node->right;
}
Node* successor(Node* node) {
Node* temp = node;
while (temp->left != nullptr) temp = temp->left;
return temp;
}
void fixViolation(Node* node) {
Node* parent = nullptr;
Node* grandParent = nullptr;
while (node != root && node->color == RED && node->parent->color == RED) {
parent = node->parent;
grandParent = parent->parent;
if (parent == grandParent->left) {
Node* uncle = grandParent->right;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
} else {
if (node == parent->right) {
rotateLeft(parent);
node = parent;
parent = node->parent;
}
rotateRight(grandParent);
std::swap(parent->color, grandParent->color);
node = parent;
}
} else {
Node* uncle = grandParent->left;
if (uncle != nullptr && uncle->color == RED) {
grandParent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
node = grandParent;
} else {
if (node == parent->left) {
rotateRight(parent);
node = parent;
parent = node->parent;
}
rotateLeft(grandParent);
std::swap(parent->color, grandParent->color);
node = parent;
}
}
}
root->color = BLACK;
}
void fixDoubleBlack(Node* node) {
if (node == root) return;
Node* sibling = node->sibling();
Node* parent = node->parent;
if (sibling == nullptr) {
fixDoubleBlack(parent);
} else {
if (sibling->color == RED) {
parent->color = RED;
sibling->color = BLACK;
if (sibling == parent->left) {
rotateRight(parent);
} else {
rotateLeft(parent);
}
fixDoubleBlack(node);
} else {
if (sibling->hasRedChild()) {
if (sibling->left != nullptr && sibling->left->color == RED) {
if (sibling == parent->left) {
sibling->left->color = sibling->color;
sibling->color = parent->color;
rotateRight(parent);
} else {
sibling->left->color = parent->color;
rotateRight(sibling);
rotateLeft(parent);
}
} else {
if (sibling == parent->left) {
sibling->right->color = parent->color;
rotateLeft(sibling);
rotateRight(parent);
} else {
sibling->right->color = sibling->color;
sibling->color = parent->color;
rotateLeft(parent);
}
}
parent->color = BLACK;
} else {
sibling->color = RED;
if (parent->color == BLACK) {
fixDoubleBlack(parent);
} else {
parent->color = BLACK;
}
}
}
}
}
void rotateLeft(Node* node) {
Node* rightNode = node->right;
node->right = rightNode->left;
if (node->right != nullptr) node->right->parent = node;
rightNode->parent = node->parent;
if (node->parent == nullptr) root = rightNode;
else if (node == node->parent->left) node->parent->left = rightNode;
else node->parent->right = rightNode;
rightNode->left = node;
node->parent = rightNode;
}
void rotateRight(Node* node) {
Node* leftNode = node->left;
node->left = leftNode->right;
if (node->left != nullptr) node->left->parent = node;
leftNode->parent = node->parent;
if (node->parent == nullptr) root = leftNode;
else if (node == node->parent->left) node->parent->left = leftNode;
else node->parent->right = leftNode;
leftNode->right = node;
node->parent = leftNode;
}
void inorderHelper(Node* root) {
if (root == nullptr) return;
inorderHelper(root->left);
std::cout << root->data << " ";
inorderHelper(root->right);
}
void generateGraphvizHelper(std::ofstream& file, Node* root) {
if (root->left != nullptr) {
file << root->data << " -> " << root->left->data << ";\n";
generateGraphvizHelper(file, root->left);
} else {
file << "null" << root->data << "L [shape=point];\n";
file << root->data << " -> null" << root->data << "L;\n";
}
if (root->right != nullptr) {
file << root->data << " -> " << root->right->data << ";\n";
generateGraphvizHelper(file, root->right);
} else {
file << "null" << root->data << "R [shape=point];\n";
file << root->data << " -> null" << root->data << "R;\n";
}
}
};
int main() {
RedBlackTree tree;
tree.insert(10);
tree.insert(20);
tree.insert(30);
tree.insert(15);
tree.insert(25);
tree.insert(5);
tree.generateGraphviz("rbtree.dot");
std::cout << "Graphviz dot file generated as rbtree.dot" << std::endl;
return 0;
}
cpp
// Output
digraph G {
10 -> 5;
10 -> 20;
20 -> 15;
20 -> 30;
30 -> 25;
null5L [shape=point];
5 -> null5L;
null5R [shape=point];
5 -> null5R;
null15L [shape=point];
15 -> null15L;
null15R [shape=point];
15 -> null15R;
null25L [shape=point];
25 -> null25L;
null25R [shape=point];
25 -> null25R;
null30L [shape=point];
30 -> null30L;
null30R [shape=point];
30 -> null30R;
}
10
/ \
5 20
/ \
15 30
/
25
总结
红黑树(Red-Black Tree)是一种自平衡二叉搜索树,常用于需要高效插入、删除和查找操作的数据结构中。红黑树的特点包括每个节点是红色或黑色、根节点是黑色、红色节点的子节点必须是黑色、从任一节点到其每个叶子节点的路径上的黑色节点数目相同。