文章目录
红黑树
红黑树的概念
红黑树 ,是一种二叉搜索树 ,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black 。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍 ,因而是接近平衡 的。

红黑树的性质
- 每个节点不是红色就是黑色。
- 根节点是黑色。
- 如果一个节点是红色,则它的两个孩子节点是黑色。
- 对每个节点,从该节点到所有后代叶节点的简单路径上,黑色节点数目相同。
- 每个叶子节点(空节点)都是黑色。
上述5点性质是构建红黑树的必要条件,那么为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?
我们设最短路径黑色节点数为 bh。
- 最短路径可以全是黑色,长度为
bh。因为根节点是黑色且叶子都是黑色,但是并没有规定非叶子节点不能为黑色,那么最短路径就可以全是黑色。 - 最长路径可以红黑交替,因为它可以连续黑,但不能有连续红节点,且黑色节点数也为
bh。 - 最长路径最多有
bh个黑节点和bh个红节点,总长度最多 2bh。 - 所以最长路径 <= 2 * 最短路径。
红黑树节点的定义
cpp
enum Color { RED, BLACK };
template<class ValueType>
struct RBTreeNode {
RBTreeNode(const ValueType& data = ValueType(), Color color = RED)
: _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr),
_data(data), _color(color) {}
RBTreeNode<ValueType>* _pLeft;
RBTreeNode<ValueType>* _pRight;
RBTreeNode<ValueType>* _pParent;
ValueType _data;
Color _color;
};
红黑树结构
这里节点的定义是为了后续实现关联式容器简单,给红黑树实现增加一个头节点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点,如下:

红黑树的插入操作
红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
- 按二叉搜索树(BST)规则插入
- 如果是空树,新节点作为根节点,直接涂黑。
- 如果非空,按BST规则找到位置插入,默认涂红。
- 插入后,检查是否破坏了红黑树性质。如果父节点是黑色,则无需调整;如果父节点是红色,则违反了性质3,需要进行调整。
为什么非空插入节点默认涂红?
因为如果插入黑色节点,一定会改变某条路径的黑色节点数量,违反性质 4,几乎必须调整。
如果插入红色节点,只有父节点也是红色时才违反性质 3,调整概率更低,且调整更简单。
- 红黑树的平衡调整
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点(p的兄弟节点)。
触发调整的条件:p为红,g必为黑(因为不能有连续红节点)。
根据u的颜色和cur的位置,分为三种情况:-
情况一:叔叔
u存在且为红-
特征:
cur红,p红,g黑,u红。 -
需注意下图可能是完整的树,也可能是一颗子树

-
处理方式(只变色,不旋转):
- 将
p变黑。 - 将
u变黑。 - 将
g变红。
- 将
-
后续:将
g作为新的cur,继续向上调整。如果g是根节点,最后需强制变黑。 -
为什么这么做? 如果只把
p改黑,会导致p所在路径黑节点数+1,破坏性质4。所以必须把u也改黑,再让g变红,保持整体黑高不变。
-
-
情况二:叔叔
u不存在 或u存在且为黑,且cur、p、g在同一条直线上(共线)-
特征:
p红,u黑/无,g黑。cur和p同为左孩子或同为右孩子。
-
处理方式(旋转 + 变色):
- 若
p是g的左孩子 ,cur是p的左孩子 :对g进行右单旋。 - 若
p是g的右孩子 ,cur是p的右孩子 :对g进行左单旋。
- 若
-
**变色:**旋转后,将
p变黑,g变红。 -
**注意:**此时局部根节点变为
p(黑),且解决了连续红节点的问题。
-
-
情况三:叔叔 u 不存在 或 u 存在且为黑,且
cur、p、g不在同一条直线上(折线)-
特征:
p红,u黑/无,g黑。cur和p一个是左孩子,一个是右孩子。
-
处理方式(双旋 + 变色):
- 若
p是g的左孩子 ,cur是p的右孩子 :对p进行左单旋。 - 若
p是g的右孩子 ,cur是p的左孩子 :对p进行右单旋。
- 若
-
后续: 旋转后,交换
cur和p的指针 。此时结构变成了情况二 (共线),然后再按照情况二进行处理(对g旋转并变色)
-
-
cpp
bool Insert(const ValueType& data) {
Node*& pRoot = GetRoot();
if (pRoot == nullptr) {
pRoot = new Node(data, BLACK);
pRoot->_pParent = _pHead;
_pHead->_pParent = pRoot;
_pHead->_pLeft = pRoot;
_pHead->_pRight = pRoot;
return true;
}
Node* parent = nullptr;
Node* cur = pRoot;
while (cur) {
if (data < cur->_data) {
parent = cur;
cur = cur->_pLeft;
}
else if (data > cur->_data) {
parent = cur;
cur = cur->_pRight;
}
else {
return false;
}
}
cur = new Node(data, RED);
cur->_pParent = parent;
if (data < parent->_data)
parent->_pLeft = cur;
else
parent->_pRight = cur;
while (parent && parent->_color == RED) {
Node* grandFather = parent->_pParent;
if (parent == grandFather->_pLeft) {
Node* uncle = grandFather->_pRight;
if (uncle && uncle->_color == RED) {
parent->_color = BLACK;
uncle->_color = BLACK;
grandFather->_color = RED;
cur = grandFather;
parent = cur->_pParent;
}
else {
if (cur == parent->_pRight) {
RotateL(parent);
swap(parent, cur);
}
grandFather->_color = RED;
parent->_color = BLACK;
RotateR(grandFather);
break;
}
}
else {
Node* uncle = grandFather->_pLeft;
if (uncle && uncle->_color == RED) {
parent->_color = BLACK;
uncle->_color = BLACK;
grandFather->_color = RED;
cur = grandFather;
parent = cur->_pParent;
}
else {
if (cur == parent->_pLeft) {
RotateR(parent);
swap(parent, cur);
}
grandFather->_color = RED;
parent->_color = BLACK;
RotateL(grandFather);
break;
}
}
}
pRoot->_color = BLACK;
_pHead->_pLeft = LeftMost();
_pHead->_pRight = RightMost();
return true;
}
红黑树的验证
红黑树的检测分为两步:
- 检测其是否满足二叉搜索树(中序遍历是否为有序序列)
- 检测其是否满足红黑树的性质
cpp
bool IsValidRBTree() {
Node* pRoot = GetRoot();
if (pRoot == nullptr) return true;
if (pRoot->_color != BLACK) {
cout << "违反性质2:根不是黑色" << endl;
return false;
}
size_t blackCount = 0;
Node* cur = pRoot;
while (cur) {
if (cur->_color == BLACK) ++blackCount;
cur = cur->_pLeft;
}
size_t k = 0;
return _IsValidRBTree(pRoot, k, blackCount);
}
bool _IsValidRBTree(Node* root, size_t k, size_t blackCount) {
if (root == nullptr) {
if (k != blackCount) {
cout << "违反性质4:黑高不同" << endl;
return false;
}
return true;
}
if (root->_color == BLACK) ++k;
Node* parent = root->_pParent;
if (parent && parent->_color == RED && root->_color == RED) {
cout << "违反性质3:红红相连" << endl;
return false;
}
return _IsValidRBTree(root->_pLeft, k, blackCount) &&
_IsValidRBTree(root->_pRight, k, blackCount);
}
红黑树完整代码
cpp
#pragma once
#include <iostream>
#include <utility>
using namespace std;
enum Color { RED, BLACK };
template<class ValueType>
struct RBTreeNode {
RBTreeNode(const ValueType& data = ValueType(), Color color = RED)
: _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr),
_data(data), _color(color) {
}
RBTreeNode<ValueType>* _pLeft;
RBTreeNode<ValueType>* _pRight;
RBTreeNode<ValueType>* _pParent;
ValueType _data;
Color _color;
};
template<class ValueType>
class RBTree {
typedef RBTreeNode<ValueType> Node;
public:
RBTree() {
_pHead = new Node;
_pHead->_color = BLACK;
_pHead->_pLeft = _pHead;
_pHead->_pRight = _pHead;
_pHead->_pParent = nullptr;
}
~RBTree()
{
Clear();
delete _pHead;
}
bool Insert(const ValueType& data) {
Node*& pRoot = GetRoot();
if (pRoot == nullptr) {
pRoot = new Node(data, BLACK);
pRoot->_pParent = _pHead;
_pHead->_pParent = pRoot;
_pHead->_pLeft = pRoot;
_pHead->_pRight = pRoot;
return true;
}
Node* parent = nullptr;
Node* cur = pRoot;
while (cur) {
if (data < cur->_data) {
parent = cur;
cur = cur->_pLeft;
}
else if (data > cur->_data) {
parent = cur;
cur = cur->_pRight;
}
else {
return false;
}
}
cur = new Node(data, RED);
cur->_pParent = parent;
if (data < parent->_data)
parent->_pLeft = cur;
else
parent->_pRight = cur;
while (parent && parent->_color == RED) {
Node* grandFather = parent->_pParent;
if (parent == grandFather->_pLeft) {
Node* uncle = grandFather->_pRight;
if (uncle && uncle->_color == RED) {
parent->_color = BLACK;
uncle->_color = BLACK;
grandFather->_color = RED;
cur = grandFather;
parent = cur->_pParent;
}
else {
if (cur == parent->_pRight) {
RotateL(parent);
swap(parent, cur);
}
grandFather->_color = RED;
parent->_color = BLACK;
RotateR(grandFather);
break;
}
}
else {
Node* uncle = grandFather->_pLeft;
if (uncle && uncle->_color == RED) {
parent->_color = BLACK;
uncle->_color = BLACK;
grandFather->_color = RED;
cur = grandFather;
parent = cur->_pParent;
}
else {
if (cur == parent->_pLeft) {
RotateR(parent);
swap(parent, cur);
}
grandFather->_color = RED;
parent->_color = BLACK;
RotateL(grandFather);
break;
}
}
}
pRoot->_color = BLACK;
_pHead->_pLeft = LeftMost();
_pHead->_pRight = RightMost();
return true;
}
bool IsValidRBTree() {
Node* pRoot = GetRoot();
if (pRoot == nullptr) return true;
if (pRoot->_color != BLACK) {
cout << "违反性质2:根不是黑色" << endl;
return false;
}
size_t blackCount = 0;
Node* cur = pRoot;
while (cur) {
if (cur->_color == BLACK) ++blackCount;
cur = cur->_pLeft;
}
size_t k = 0;
return _IsValidRBTree(pRoot, k, blackCount);
}
private:
Node*& GetRoot() { return _pHead->_pParent; }
Node* LeftMost() {
Node* cur = GetRoot();
if (!cur) return _pHead;
while (cur->_pLeft) cur = cur->_pLeft;
return cur;
}
Node* RightMost() {
Node* cur = GetRoot();
if (!cur) return _pHead;
while (cur->_pRight) cur = cur->_pRight;
return cur;
}
void RotateL(Node* parent) {
Node* subR = parent->_pRight;
Node* subRL = subR->_pLeft;
parent->_pRight = subRL;
if (subRL) subRL->_pParent = parent;
subR->_pLeft = parent;
Node* ppNode = parent->_pParent;
parent->_pParent = subR;
subR->_pParent = ppNode;
if (ppNode == _pHead)
_pHead->_pParent = subR;
else if (ppNode->_pLeft == parent)
ppNode->_pLeft = subR;
else
ppNode->_pRight = subR;
}
void RotateR(Node* parent) {
Node* subL = parent->_pLeft;
Node* subLR = subL->_pRight;
parent->_pLeft = subLR;
if (subLR) subLR->_pParent = parent;
subL->_pRight = parent;
Node* ppNode = parent->_pParent;
parent->_pParent = subL;
subL->_pParent = ppNode;
if (ppNode == _pHead)
_pHead->_pParent = subL;
else if (ppNode->_pLeft == parent)
ppNode->_pLeft = subL;
else
ppNode->_pRight = subL;
}
bool _IsValidRBTree(Node* root, size_t k, size_t blackCount) {
if (root == nullptr) {
if (k != blackCount) {
cout << "违反性质4:黑高不同" << endl;
return false;
}
return true;
}
if (root->_color == BLACK) ++k;
Node* parent = root->_pParent;
if (parent && parent->_color == RED && root->_color == RED) {
cout << "违反性质3:红红相连" << endl;
return false;
}
return _IsValidRBTree(root->_pLeft, k, blackCount) &&
_IsValidRBTree(root->_pRight, k, blackCount);
}
void Clear() {
_Clear(GetRoot());
GetRoot() = nullptr;
_pHead->_pLeft = _pHead;
_pHead->_pRight = _pHead;
}
void _Clear(Node* root) {
if (!root) return;
_Clear(root->_pLeft);
_Clear(root->_pRight);
delete root;
}
private:
Node* _pHead;
};
红黑树与AVL树的比较
| 比较维度 | AVL树 | 红黑树 |
|---|---|---|
| 平衡标准 | 严格平衡(左右子树高度差绝对值不超过1) | 弱平衡(最长路径不超过最短路径的2倍) |
| 树的高度 | 最低,高度约为 ( 1.44 l o g 2 N (1.44log_2 N (1.44log2N) | 略高,高度约为 ( 2 l o g 2 N (2log_2 N (2log2N) |
| 查找效率 | 极高(由于树更矮,查找所需比较次数更少) | 较高(略逊于AVL树,但依然是 ( O ( l o g N ) (O(log N) (O(logN))) |
| 插入/删除效率 | 较低(为了维持严格平衡,可能需要频繁旋转) | 较高(调整次数少,只需少量的变色和最多3次旋转) |
| 插入旋转次数 | 最多 1 次旋转(单旋或双旋) | 最多 2 次旋转 |
| 删除旋转次数 | 最坏情况需要 ( O ( l o g N ) (O(log N) (O(logN)) 次旋转(一路旋转到根节点) | 最多 3 次旋转 |
| 节点存储开销 | 需要额外存储平衡因子或高度 | 需要额外存储颜色 |
| 实现复杂度 | 插入和删除逻辑较复杂,需维护平衡因子 | 插入和删除逻辑(尤其是情况分支)较多,但调整较规律 |
| 适用场景 | 查找密集型场景(查多改少) | 插入、删除频繁的场景(查改均衡或改多) |
| 典型应用 | Windows NT内核(早期)、数据库索引(部分) | C++ STL (map, set, multimap, multiset)、Java TreeMap、HashMap(链表转红黑树)、Linux内核调度器/文件系统、Nginx |
完