目录
[4.1 插入流程图](#4.1 插入流程图)
[4.2 插入代码分段详解](#4.2 插入代码分段详解)
[5.1 情况一:叔叔节点为红色](#5.1 情况一:叔叔节点为红色)
[5.2 情况二:叔叔节点为黑色或不存在(cur是parent的右孩子)](#5.2 情况二:叔叔节点为黑色或不存在(cur是parent的右孩子))
[5.3 情况三:叔叔节点为黑色或不存在(cur是parent的左孩子)](#5.3 情况三:叔叔节点为黑色或不存在(cur是parent的左孩子))
[5.4 对称情况](#5.4 对称情况)
[6.1 左单旋(RotateLeft)](#6.1 左单旋(RotateLeft))
[6.2 右单旋(RotateRight)](#6.2 右单旋(RotateRight))
[7.1 检查流程](#7.1 检查流程)
[7.2 递归检查函数](#7.2 递归检查函数)
一、红黑树概述
红黑树是一种自平衡的二叉搜索树 ,它在每个节点上增加一个存储位表示节点的颜色(红或黑)。通过对任何一条从根到叶子的路径上节点颜色的约束,红黑树确保最长路径不超过最短路径的2倍,从而保持近似平衡。
二、红黑树的五大性质
| 性质 | 描述 | 代码中的体现 |
|---|---|---|
| 性质1 | 每个节点是红色或黑色 | enum Colour { RED, BLACK }; |
| 性质2 | 根节点是黑色 | _root->_col = BLACK; 强制保证 |
| 性质3 | 所有叶子节点(NIL)是黑色 | 代码中 nullptr 视为黑色节点 |
| 性质4 | 红色节点的子节点必须是黑色 | Check() 函数检查连续红色 |
| 性质5 | 从任一节点到其每个叶子的路径包含相同数量的黑色节点 | Check() 函数验证每条路径黑色节点数相等 |
三、节点结构设计
cpp
template<class K, class V>
struct RBTreeNode
{
pair<K, V> _kv; // 键值对
RBTreeNode<K, V>* _left; // 左孩子
RBTreeNode<K, V>* _right; // 右孩子
RBTreeNode<K, V>* _parent; // 父节点(重要!)
Colour _col; // 颜色
RBTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED) // 新节点默认为红色
{}
};
为什么新节点默认为红色?
如果插入黑色节点,会破坏性质5(黑色节点数量),影响所有路径
插入红色节点只可能破坏性质4(连续红色),影响范围更小,更容易调整
四、插入操作核心逻辑
4.1 插入流程图

4.2 插入代码分段详解
步骤1:空树处理
cpp
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK; // 根节点必须为黑色
return true;
}
步骤2:BST插入
cpp
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false; // 键值重复,插入失败
}
}
cur = new Node(kv); // 创建红色新节点
if (kv.first < parent->_kv.first)
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
步骤3:调整红黑树性质
这是最核心的部分,我们根据父节点是祖父的左孩子还是右孩子 分两种情况,每种情况再根据叔叔节点的颜色分三种子情况。
五、插入调整的三种情况详解
情况定义
cur:当前新插入节点(红色)
parent:父节点(红色,需要调整)
grandfather:祖父节点(必为黑色)
uncle:叔叔节点(祖父的另一子)
5.1 情况一:叔叔节点为红色
特征 :uncle 存在且为红色

处理方式:
将
parent和uncle改为黑色将
grandfather改为红色将
cur指向grandfather,继续向上调整
代码实现:
cpp
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
5.2 情况二:叔叔节点为黑色或不存在(cur是parent的右孩子)
特征:
uncle不存在或为黑色
cur是parent的右孩子(需要双旋)

处理方式:
对
parent进行左单旋交换
parent和cur指针转化为情况三
代码实现:
cpp
if (cur == parent->_right)
{
RotateLeft(parent); // 左旋
swap(parent, cur); // 交换,转化为情况三
}
// 接着执行情况三...
5.3 情况三:叔叔节点为黑色或不存在(cur是parent的左孩子)
特征:
uncle不存在或为黑色
cur是parent的左孩子(单旋即可)

处理方式:
对
grandfather进行右单旋将
parent改为黑色将
grandfather改为红色
代码实现:
cpp
RotateRight(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
break; // 调整结束
5.4 对称情况
当
parent是grandfather的右孩子时,处理方式对称:
情况二:
cur是左孩子时,先右旋情况三:
cur是右孩子时,左旋
六、旋转操作详解
6.1 左单旋(RotateLeft)
适用场景:右子树过高,需要降低
cpp
void RotateLeft(Node* parent)
{
Node* subR = parent->_right; // 右孩子
Node* subRL = subR->_left; // 右孩子的左子树
// 1. 将subRL挂到parent的右边
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
// 2. 将parent挂到subR的左边
subR->_left = parent;
parent->_parent = subR;
// 3. 处理父指针
Node* ppNode = parent->_parent;
if (ppNode == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
6.2 右单旋(RotateRight)
适用场景:左子树过高,需要降低
cpp
void RotateRight(Node* parent)
{
Node* subL = parent->_left; // 左孩子
Node* subLR = subL->_right; // 左孩子的右子树
// 1. 将subLR挂到parent的左边
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
// 2. 将parent挂到subL的右边
subL->_right = parent;
parent->_parent = subL;
// 3. 处理父指针
Node* ppNode = parent->_parent;
if (ppNode == nullptr)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
七、平衡性检查(IsBalanceTree)
7.1 检查流程
cpp
bool IsBalanceTree()
{
if (_root == nullptr) return true;
// 1. 检查根节点颜色
if (_root->_col == RED) return false;
// 2. 计算参考值(最左路径的黑色节点数)
int refNum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK) ++refNum;
cur = cur->_left;
}
// 3. 递归检查所有路径
return Check(_root, 0, refNum);
}
7.2 递归检查函数
cpp
bool Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr)
{
// 到达叶子,检查黑色节点数是否等于参考值
if (refNum != blackNum)
{
cout << "存在黑色结点数量不相等的路径" << endl;
return false;
}
return true;
}
// 检查是否有连续红色节点
if (root->_col == RED && root->_parent && root->_parent->_col == RED)
{
cout << root->_kv.first << "存在连续的红色结点" << endl;
return false;
}
// 统计黑色节点
if (root->_col == BLACK)
blackNum++;
// 递归检查左右子树
return Check(root->_left, blackNum, refNum)
&& Check(root->_right, blackNum, refNum);
}
八、红黑树与AVL树对比
| 特性 | 红黑树 | AVL树 |
|---|---|---|
| 平衡条件 | 最长路径 ≤ 2×最短路径 | 左右子树高度差 ≤ 1 |
| 平衡程度 | 近似平衡 | 严格平衡 |
| 查询效率 | O(log n),略慢 | O(log n),更快 |
| 插入/删除效率 | 旋转次数少,更快 | 旋转次数多,较慢 |
| 适用场景 | 插入删除频繁 | 查询频繁 |
九、完整代码实现
cpp
#pragma once
#include <iostream>
using namespace std;
// 枚举值表示颜色
enum Colour
{
RED,
BLACK
};
// 这里我们默认按key/value结构实现
template<class K, class V>
struct RBTreeNode
{
// 这里更新控制平衡也要加入parent指针
pair<K, V> _kv;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED) // 新节点默认为红色
{}
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv)
{
// 1. 空树:直接创建根节点,颜色为黑色
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
// 2. 按照二叉搜索树规则插入
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false; // 键值重复,插入失败
}
}
// 创建新节点(红色)
cur = new Node(kv);
if (kv.first < parent->_kv.first)
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
// 3. 调整颜色和旋转,维持红黑树性质
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (grandfather == nullptr)
break;
// 情况一:parent 是 grandfather 的左孩子
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// 情况1:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // 情况2/3:叔叔不存在或为黑
{
// 情况2:cur 是 parent 的右孩子 -> 左单旋
if (cur == parent->_right)
{
RotateLeft(parent);
swap(parent, cur);
}
// 情况3:cur 是 parent 的左孩子 -> 右单旋
RotateRight(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
break; // 调整结束
}
}
else // 情况二:parent 是 grandfather 的右孩子(对称情况)
{
Node* uncle = grandfather->_left;
// 情况1:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
// 情况2:cur 是 parent 的左孩子 -> 右单旋
if (cur == parent->_left)
{
RotateRight(parent);
swap(parent, cur);
}
// 情况3:cur 是 parent 的右孩子 -> 左单旋
RotateLeft(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
break;
}
}
}
// 确保根节点为黑色
_root->_col = BLACK;
return true;
}
// 左单旋
void RotateLeft(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (ppNode == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
}
// 右单旋
void RotateRight(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (ppNode == nullptr)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalanceTree()
{
if (_root == nullptr)
return true;
if (_root->_col == RED)
return false;
// 计算最左路径的黑色节点数作为参考值
int refNum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
++refNum;
cur = cur->_left;
}
return Check(_root, 0, refNum);
}
private:
Node* _root = nullptr;
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << " ";
_InOrder(root->_right);
}
bool Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr)
{
if (refNum != blackNum)
{
cout << "存在黑色结点数量不相等的路径" << endl;
return false;
}
return true;
}
// 检查是否有连续红色节点
if (root->_col == RED && root->_parent && root->_parent->_col == RED)
{
cout << root->_kv.first << "存在连续的红色结点" << endl;
return false;
}
if (root->_col == BLACK)
blackNum++;
return Check(root->_left, blackNum, refNum)
&& Check(root->_right, blackNum, refNum);
}
};