红黑树详解初版
一、红黑树核心性质
红黑树是自平衡二叉搜索树,需满足5条性质:
- 节点非红即黑
- 根节点必须为黑
- 叶子节点(NIL)均为黑
- 红色节点子节点必为黑(无连续红节点)
- 任意节点到叶子路径的黑节点数相同(黑高度一致)
二、C++节点结构定义
enum Colour { RED, BLACK };template <typename K, typename V>
struct RBTreeNode {K key;V value;Colour color;RBTreeNode *left, *right, *parent;RBTreeNode(K k, V v) : key(k), value(v), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};
节点默认红色以最小化插入调整代价
三、插入操作详解
步骤1:二叉搜索树插入
bool Insert(const pair<K, V>& kv) {if (!root) { root = new Node(kv, BLACK); return true; }// 查找插入位置(同普通BST)//...// 新节点插入为红色cur = new Node(kv);cur->color = RED;parent->left/right = cur;cur->parent = parent;// 进入调整逻辑FixInsert(cur);
}
步骤2:插入后调整(FixInsert)
情况1:叔节点为红
处理方案:
父、叔变黑,祖父变红,递归处理祖父节点
parent->color = uncle->color = BLACK;
grandfather->color = RED;
cur = grandfather; // 向上递归
情况2:叔节点为黑(直线型)
处理方案:
祖父右旋,父变黑,祖父变红
RotateR(grandfather);
parent->color = BLACK;
grandfather->color = RED;
情况3:叔节点为黑(折线型)
处理方案:
先左旋父节点转换为直线型,再按情况2处理
RotateL(parent);
RotateR(grandfather);
四、删除操作核心逻辑
步骤1:BST标准删除
void Delete(K key) {Node* target = Search(key);if (!target) return;// 处理单子节点/叶子节点删除//...// 若删除黑色节点需进入双黑修正if (target->color == BLACK) FixDoubleBlack(replacement);
}
步骤2:双黑修正(FixDoubleBlack)
情况1:兄弟节点为红
处理方案:
父节点左旋,兄弟变黑,父变红
RotateL(parent);
sibling->color = BLACK;
parent->color = RED;
情况2:兄弟节点为黑且远侄子为红
处理方案:
父节点左旋,远侄子变黑,父继承原父颜色
RotateL(parent);
sibling->right->color = BLACK;
parent->color = original_color;
五、旋转操作代码实现
左旋示例:
关键步骤解析:
- 原父节点P的右子节点Y上升为新父节点
- 将Y的左子树α挂载到X的右子树
- 原父节点P的右指针指向Y
- Y的左指针指向X(形成父子关系反转)
void RotateL(Node* x) {Node* y = x->right;x->right = y->left;if (y->left) y->left->parent = x;y->parent = x->parent;if (!x->parent) root = y;else if (x == x->parent->left) x->parent->left = y;else x->parent->right = y;y->left = x;x->parent = y;
}
右旋对称实现
六、示例
七、完整代码
#include <iostream>
using namespace std;enum Colour { RED, BLACK };template<class K, class V>
struct RBTreeNode {pair<K, V> _kv;Colour _col;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;RBTreeNode(const pair<K, V>& kv): _kv(kv),_col(RED),_left(nullptr),_right(nullptr),_parent(nullptr) {}
};template<class K, class V>
class RBTree {typedef RBTreeNode<K, V> Node;
public:RBTree() {NIL = new Node(make_pair(K(), V()));NIL->_col = BLACK;_root = NIL;}bool Insert(const pair<K, V>& kv) {if (_root == NIL) {_root = new Node(kv);_root->_col = BLACK;_root->_left = _root->_right = NIL;return true;}Node* parent = NIL;Node* cur = _root;while (cur != NIL) {parent = cur;if (cur->_kv.first > kv.first)cur = cur->_left;else if (cur->_kv.first < kv.first)cur = cur->_right;elsereturn false;}Node* newNode = new Node(kv);newNode->_left = newNode->_right = NIL;if (parent->_kv.first > kv.first)parent->_left = newNode;elseparent->_right = newNode;newNode->_parent = parent;FixInsert(newNode);return true;}private:Node* _root;Node* NIL; // 哨兵节点[2,4]// 左旋修正void RotateL(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 == NIL)_root = y;else if (x == x->_parent->_left)x->_parent->_left = y;elsex->_parent->_right = y;y->_left = x;x->_parent = y;}// 右旋修正void RotateR(Node* x) {Node* y = x->_left;x->_left = y->_right;if (y->_right != NIL)y->_right->_parent = x;y->_parent = x->_parent;if (x->_parent == NIL)_root = y;else if (x == x->_parent->_right)x->_parent->_right = y;elsex->_parent->_left = y;y->_right = x;x->_parent = y;}void FixInsert(Node* z) {while (z->_parent->_col == RED) {Node* g = z->_parent->_parent;if (z->_parent == g->_left) {Node* u = g->_right;if (u->_col == RED) { // Case 1z->_parent->_col = BLACK;u->_col = BLACK;g->_col = RED;z = g;} else {if (z == z->_parent->_right) { // Case 2z = z->_parent;RotateL(z);}// Case 3z->_parent->_col = BLACK;g->_col = RED;RotateR(g);}} else { // 对称处理[4,6]Node* u = g->_left;if (u->_col == RED) {z->_parent->_col = BLACK;u->_col = BLACK;g->_col = RED;z = g;} else {if (z == z->_parent->_left) {z = z->_parent;RotateR(z);}z->_parent->_col = BLACK;g->_col = RED;RotateL(g);}}if (z == _root) break;}_root->_col = BLACK; // 强制根节点为黑[4,8]}
};// 测试用例
int main() {RBTree<int, int> tree;// 测试插入序列(触发所有修复情况)int arr[] = {10, 20, 30, 40, 50, 60, 70, 80, 90};for (auto num : arr) {tree.Insert(make_pair(num, num));}return 0;
}
八、应用场景
- C++ STL:
map
/set
底层实现 - Java集合:
TreeMap
的平衡机制 - Linux内核:进程调度CFS算法