上一章节我们实现了AVL树,这一章节我们就来实现一下红黑树,同样这里我们只介绍插入和查找的接口,插入是构建红黑树的关键,同时也是常考的点,至于为什么删除会显得”并不重要“,原因如下:
I. 应用场景中插入频率远高于删除
II. 删除操作可通过策略优化绕过复杂度
ConcurrentHashMap)。
III. 删除的实现复杂度更高,但触发条件更少
IV. 性能优化的侧重点不同
V. 红黑树的设计哲学
总结:为什么删除显得“不重要”?
维度 | 插入 | 删除 |
|---|---|---|
频率 | 高(实时数据流、动态更新) | 低(常被惰性删除或批量处理) |
修复复杂度 | 简单(4种Case,局部修复) | 复杂(6+种Case,可能递归调整) |
优化策略 | 直接决定实时性能 | 常被延迟或分摊处理 |
设计目标 | 确保高频操作高效 | 容忍低频操作的较高成本 |
红黑树是一种二叉搜索树,每个节点新增一个存储位来表示节点颜色,可以是红色或黑色。
通过对从根节点到叶节点的每条路径上的节点颜色进行约束,红黑树确保没有路径会比其他路径长两倍以上,因此是近似平衡的。




以上这些都是红黑树
注:《算法导论》等书籍补充了一条规则:所有叶节点(NIL)必须是黑色。这里的叶节点并非传统意义上的叶节点,而是指空节点(也被称为外部节点)。NIL节点的引入是为了准确标识所有路径,但在实际实现细节中《算法导论》也忽略了NIL节点,了解这个概念即可。

红黑树通过以下规则保证其平衡性:
设N为红黑树中的节点总数,h为红黑树的最短路径长度(即黑色高度)。根据红黑树的以下关键性质:
可以得出数学关系式: 2^h - 1 ≤ N < 2^(2h) - 1
这个不等式右边2^(2h)是因为红黑树的最长路径可能达到2h(红黑交替)。通过数学推导可得树的近似高度范围: h ≈ log₂N → 2log₂N
这意味着红黑树的增删查改操作在最坏情况下只需遍历最长路径(高度不超过2log₂N),时间复杂度保持为O(logN)。例如:
与AVL树的对比分析:
实际应用中的选择标准:

Colourenum Colour
{
RED,
BLACK
};RBTreeNodetemplate<class K, class V>
struct RBTreeNode
{
RBTreeNode(const pair<K, V>& kv)
:_kv(kv)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_col(RED) // 新节点默认红色(符合红黑树插入规则)
{}
pair<K, V> _kv; // 键值对
RBTreeNode<K, V>* _left; // 左子节点
RBTreeNode<K, V>* _right;// 右子节点
RBTreeNode<K, V>* _parent; // 父节点
Colour _col; // 节点颜色
};关键点:
pair<K, V> 存储键值。
_left、_right、_parent 指针,便于回溯和调整树结构。
RBTreetemplate<class K, class V>
class RBTree
{
using Node = RBTreeNode<K, V>; // 类型别名简化代码
public:
private:
Node* _root = nullptr; // 根节点初始化为空
};设计分析:
K 和 V),类似 STL 的 map。
_root 表示树的根,初始为空。
Insert)需处理颜色调整和旋转。
Find)基于二叉搜索树规则。
RotateLeft、右旋 RotateRight)。
具体代码:
enum Colour
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED) // 新节点默认红色(符合红黑树插入规则)
{}
pair<K, V> _kv; // 键值对
RBTreeNode<K, V>* _left; // 左子节点
RBTreeNode<K, V>* _right;// 右子节点
RBTreeNode<K, V>* _parent; // 父节点
Colour _col; // 节点颜色
};
template<class K, class V>
class RBTree
{
using Node = RBTreeNode<K, V>;
public:
private:
Node* _root = nullptr;
};旋转和AVL树的逻辑是一样的,不过只需要旋转树节点,不需要去维护平衡因子,所以具体细节就不再细讲,感兴趣可以去上一章节AVL树的实现中查看
旋转代码:
// 右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;// parent的左子节点(旋转后的新根)
Node* subLR = subL->_right;// subL的右子节点(可能为空)
// 旋转节点
subL->_right = parent;
parent->_left = subLR;
// 维护父指针
Node* pParent = parent->_parent;
parent->_parent = subL;
if (subLR) //若subLR存在,更新其父指针,避免堆空指针解引用
{
subLR->_parent = parent;
}
subL->_parent = pParent;
// 维护parent的父节点
if (parent == _root) // parent为根节点的情况
{
_root = subL;
}
else // parent是一棵局部子树的情况
{
if (pParent->_left == parent)
{
pParent->_left = subL;
}
else
{
pParent->_right = subL;
}
}
}
// 左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;// parent的右子节点(旋转后的新根)
Node* subRL = subR->_left;// subR的左子节点(可能为空)
// 旋转节点
subR->_left = parent;
parent->_right = subRL;
// 维护父指针
Node* pParent = parent->_parent;
parent->_parent = subR;
if (subRL) //若subRL存在,更新其父指针,避免堆空指针解引用
{
subRL->_parent = parent;
}
subR->_parent = pParent;
// 维护parent的父节点
if (parent == _root) // parent为根节点的情况
{
_root = subR;
}
else // parent是一棵局部子树的情况
{
if (pParent->_left == parent)
{
pParent->_left = subR;
}
else
{
pParent->_right = subR;
}
}
}红黑树的插入操作分为两个主要阶段:首先执行标准的二叉搜索树插入,然后进行颜色调整和旋转操作以维持红黑树性质。具体步骤如下:
处理违反规则3的情况时,需要考察以下家族关系:
根据叔节点u的不同状态,存在三种主要处理情形:
情形1:u存在且为红色
情形2:u为黑色或不存在,且c-p-g形成"直线型"(左左或右右)
情形3:u为黑色或不存在,且c-p-g形成"之字形"(左右或右左)
注:图示约定说明
当满足以下条件时:
处理步骤:
原理分析:
特殊情况:
说明:

图0

图1

图2

图3

图4
当满足以下条件时:
若u不存在,则c必定为新增结点;若u存在且为黑色,则c原本为黑色结点,因其子树中插入新结点导致c变为红色(符合情况1:变色处理的变色规则)。
解决方案分析: 由于存在连续的红色结点(p和c),仅通过变色无法解决问题,需要进行旋转操作。具体处理方式如下:
情况1(LL型): 当p是g的左孩子且c是p的左孩子时:
情况2(RR型): 当p是g的右孩子且c是p的右孩子时:

条件:
分析: 必须将p变为黑色以解决连续红色节点问题。由于u不存在或为黑色,单纯变色无法解决问题,需要执行旋转+变色操作。
操作示例1(p为g的左子节点,c为p的右子节点):
操作示例2(p为g的右子节点,c为p的左子节点):

if (_root == nullptr) {
_root = new Node(kv); // 创建根节点(默认颜色为红色)
_root->_col = BLACK; // 后续强制修正根为黑色
return true;
}查找插入位置:
while (cur) {
if (cur->_kv.first < kv.first) { // 向右子树查找
parent = cur;
cur = cur->_right;
} else if (cur->_kv.first > kv.first) { // 向左子树查找
parent = cur;
cur = cur->_left;
} else { // 键已存在,插入失败
return false;
}
}创建新节点并挂载:
cur = new Node(kv); // 新节点默认为红色
if (parent->_kv.first < kv.first) {
parent->_right = cur; // 挂载到右子树
} else {
parent->_left = cur; // 挂载到左子树
}
cur->_parent = parent; // 维护三叉链循环条件:父节点存在且为红色(若父节点为黑色,无需调整)。
while (parent && parent->_col == RED) {
Node* grandfather = parent->_parent; // 祖父节点必存在(因父为红,不可能是根)
// 分父节点是祖父的左/右孩子两种情况处理
}获取叔节点:
Node* uncle = grandfather->_right;Case 1:叔节点存在且为红(变色处理):
if (uncle && uncle->_col == RED) {
parent->_col = uncle->_col = BLACK; // 父、叔变黑
grandfather->_col = RED; // 祖父变红
cur = grandfather; // 向上回溯
parent = cur->_parent; // 检查新的父节点
}Case 2/3:叔节点为黑或不存在(旋转+变色):
Case 2(LL型):当前节点是父的左孩子(右单旋):
if (parent->_left == cur) {
RotateR(grandfather); // 右旋祖父
grandfather->_col = RED; // 祖父变红
parent->_col = BLACK; // 父变黑
}Case 3(LR型):当前节点是父的右孩子(左右双旋):
else {
RotateL(parent); // 先左旋父节点
RotateR(grandfather); // 再右旋祖父
grandfather->_col = RED; // 祖父变红
cur->_col = BLACK; // 当前节点变黑
}结果:旋转后子树根节点变为黑色,结束调整。
处理逻辑与上述对称:
grandfather->_left。
_root->_col = BLACK; // 确保根节点始终为黑初始状态:
g(B)
/
p(R)
\
c(R) 左旋父节点:
g(B)
/
c(R)
/
p(R) 右旋祖父节点:
c(B)
/ \
p(R) g(R)颜色调整:g 变红,c 变黑,结束调整。
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
//链接父亲节点
cur->_parent = parent;
// 父节点为红色,需要颜色修正
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent; // 祖父节点必存在(因父为红,不可能是根)
// 分父节点是祖父的左/右孩子两种情况处理
if (grandfather->_left == parent)
{
// g(B)
// p(R) u(分情况)
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED) // 情况1:变色处理
{
// g(B)
// p(R) u(存在且为红色)
//c(R)
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // 情况2,3:旋转 + 变色
{
if (parent->_left == cur) // 右单旋 + 变色
{
// g(B)
// p(R) u(不存在或为黑色)
//c(R)
RotateR(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else // 左右双旋 + 变色
{
// g(B)
// p(R) u(不存在或为黑色)
// c(R)
RotateL(parent);
RotateR(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
//此时旋转之后的子树根节点为parent或cur,但都变为黑色,更新到黑结束
break;
}
}
else
{
// g(B)
// u(分情况) p(R)
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED) // 情况1:变色处理
{
// g(B)
// u(存在且为红色) p(R)
// c(R)
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // 情况2,3:旋转 + 变色
{
if (parent->_left == cur) // 左单旋 + 变色
{
// g(B)
// u(不存在或为黑色) p(R)
// c(R)
RotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else // 右左双旋 + 变色
{
// g(R)
// u(不存在或为黑色) p(R)
// c(R)
RotateR(parent);
RotateL(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
//此时旋转之后的子树根节点为parent或cur,但都变为黑色,更新到黑结束
break;
}
}
}
// 暴力处理:无论是否处理到根节点,都直接把根节点变为黑色(符合根节点为黑色规则)
_root->_col = BLACK;
return true;
}按二叉搜索树逻辑实现即可,搜索效率为 O(logN)
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}单纯通过比较最长路径和最短路径的长度(检查最长路径不超过最短路径的2倍)并不能完全验证红黑树的合法性,因为即使满足这个条件,仍可能出现颜色规则不符的情况。当前状态可能暂时没有问题,但后续插入操作仍会导致错误。因此,我们采取直接检查红黑树四大规则的方法,只要满足这四点规则,自然就能保证最长路径不超过最短路径的2倍。
验证方法如下:
1. 入口函数 _IsBalance()
bool _IsBalance()
{
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);
}refNum(红黑树要求所有路径黑节点数相同)。
Check 函数遍历所有路径。
2. 递归检查函数 Check()
bool Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr) {
if (blackNum != refNum) { // 路径黑节点数不匹配
cout << "存在黑色节点数量不相等的路径" << endl;
return false;
}
return true;
}
// 检查是否存在连续红节点
if (root->_col == RED && 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);
}nullptr 时,比较当前路径黑节点数 blackNum 与参考值 refNum。
其他高度检测,节点数量,中序遍历等直接复用AVL树的代码。
具体代码:
void InOrder()
{
_InOrder(_root);
cout << endl;
}
int Height()
{
return _Height(_root);
}
bool IsBalance()
{
return _IsBalance();
}
int Size()
{
return _Size(_root);
}
private:
int _Size(Node* root)
{
if (root == nullptr) return 0;
int leftSize = _Size(root->_left);
int rightSize = _Size(root->_right);
return leftSize + rightSize + 1;
}
int _Height(Node* root)
{
if (root == nullptr) return 0;
int leftHigh = _Height(root->_left);
int rightHigh = _Height(root->_right);
return leftHigh > rightHigh ? leftHigh + 1 : rightHigh + 1;
}
bool Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr)
{
// 前序遍历走到空时,意味着一条路径走完了
//cout << blackNum << endl;
if (refNum != blackNum)
{
cout << "存在黑色结点的数量不相等的路径" << endl;
return false;
}
return true;
}
// 检查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲就方便多了
if (root->_col == RED && 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);
}
bool _IsBalance()
{
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);
}
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}检测红黑树:
普通测试:
void TestRBTTree1()
{
RBTree<int, int> t;
// 常规的测试用例
//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
// 特殊的带有双旋场景的测试用例
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
t.Insert({ e, e });
}
t.InOrder();
cout << t.IsBalance() << endl;
}常规测试用例:

带双旋的测试用例:

生成随机数插入测试:
// 插入一堆随机值,测试平衡,顺便测试一下高度和性能等
void TestRBTTree2()
{
const int N = 100000;
vector<int> v;
v.reserve(N);
srand((unsigned int)time(0));
for (int i = 0; i < N; i++)
{
v.push_back(rand() + i);
}
size_t begin2 = clock();
RBTree<int, int> t;
for (auto e : v)
{
t.Insert(make_pair(e, e));
}
size_t end2 = clock();
cout << "Insert:" << end2 - begin2 << endl;
cout << t.IsBalance() << endl;
cout << "Height:" << t.Height() << endl;
cout << "Size:" << t.Size() << endl;
size_t begin1 = clock();
// 确定在的值
for (auto e : v)
{
t.Find(e);
}
// 随机值
/*for (int i = 0; i < N; i++)
{
t.Find((rand() + i));
}*/
size_t end1 = clock();
cout << "Find:" << end1 - begin1 << endl;
}查找确定在的值:

查找随机值:

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
enum Colour
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED) // 新节点默认红色(符合红黑树插入规则)
{}
pair<K, V> _kv; // 键值对
RBTreeNode<K, V>* _left; // 左子节点
RBTreeNode<K, V>* _right;// 右子节点
RBTreeNode<K, V>* _parent; // 父节点
Colour _col; // 节点颜色
};
template<class K, class V>
class RBTree
{
using Node = RBTreeNode<K, V>;
public:
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
//链接父亲节点
cur->_parent = parent;
// 父节点为红色,需要颜色修正
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent; // 祖父节点必存在(因父为红,不可能是根)
// 分父节点是祖父的左/右孩子两种情况处理
if (grandfather->_left == parent)
{
// g(B)
// p(R) u(分情况)
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED) // 情况1:变色处理
{
// g(B)
// p(R) u(存在且为红色)
//c(R)
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // 情况2,3:旋转 + 变色
{
if (parent->_left == cur) // 右单旋 + 变色
{
// g(B)
// p(R) u(不存在或为黑色)
//c(R)
RotateR(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else // 左右双旋 + 变色
{
// g(B)
// p(R) u(不存在或为黑色)
// c(R)
RotateL(parent);
RotateR(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
//此时旋转之后的子树根节点为parent或cur,但都变为黑色,更新到黑结束
break;
}
}
else
{
// g(B)
// u(分情况) p(R)
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED) // 情况1:变色处理
{
// g(B)
// u(存在且为红色) p(R)
// c(R)
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // 情况2,3:旋转 + 变色
{
if (parent->_right == cur) // 左单旋 + 变色
{
// g(B)
// u(不存在或为黑色) p(R)
// c(R)
RotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else // 右左双旋 + 变色
{
// g(R)
// u(不存在或为黑色) p(R)
// c(R)
RotateR(parent);
RotateL(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
//此时旋转之后的子树根节点为parent或cur,但都变为黑色,更新到黑结束
break;
}
}
}
// 暴力处理:无论是否处理到根节点,都直接把根节点变为黑色(符合根节点为黑色规则)
_root->_col = BLACK;
return true;
}
// 右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;// parent的左子节点(旋转后的新根)
Node* subLR = subL->_right;// subL的右子节点(可能为空)
// 旋转节点
subL->_right = parent;
parent->_left = subLR;
// 维护父指针
Node* pParent = parent->_parent;
parent->_parent = subL;
if (subLR) //若subLR存在,更新其父指针,避免堆空指针解引用
{
subLR->_parent = parent;
}
subL->_parent = pParent;
// 维护parent的父节点
if (parent == _root) // parent为根节点的情况
{
_root = subL;
}
else // parent是一棵局部子树的情况
{
if (pParent->_left == parent)
{
pParent->_left = subL;
}
else
{
pParent->_right = subL;
}
}
}
// 左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;// parent的右子节点(旋转后的新根)
Node* subRL = subR->_left;// subR的左子节点(可能为空)
// 旋转节点
subR->_left = parent;
parent->_right = subRL;
// 维护父指针
Node* pParent = parent->_parent;
parent->_parent = subR;
if (subRL) //若subRL存在,更新其父指针,避免堆空指针解引用
{
subRL->_parent = parent;
}
subR->_parent = pParent;
// 维护parent的父节点
if (parent == _root) // parent为根节点的情况
{
_root = subR;
}
else // parent是一棵局部子树的情况
{
if (pParent->_left == parent)
{
pParent->_left = subR;
}
else
{
pParent->_right = subR;
}
}
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
int Height()
{
return _Height(_root);
}
bool IsBalance()
{
return _IsBalance();
}
int Size()
{
return _Size(_root);
}
private:
int _Size(Node* root)
{
if (root == nullptr) return 0;
int leftSize = _Size(root->_left);
int rightSize = _Size(root->_right);
return leftSize + rightSize + 1;
}
int _Height(Node* root)
{
if (root == nullptr) return 0;
int leftHigh = _Height(root->_left);
int rightHigh = _Height(root->_right);
return leftHigh > rightHigh ? leftHigh + 1 : rightHigh + 1;
}
bool Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr)
{
// 前序遍历走到空时,意味着一条路径走完了
//cout << blackNum << endl;
if (refNum != blackNum)
{
cout << "存在黑色结点的数量不相等的路径" << endl;
return false;
}
return true;
}
// 检查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲就方便多了
if (root->_col == RED && 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);
}
bool _IsBalance()
{
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);
}
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
private:
Node* _root = nullptr;
};测试代码:
// 测试代码
void TestRBTTree1()
{
RBTree<int, int> t;
// 常规的测试用例
//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
// 特殊的带有双旋场景的测试用例
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
t.Insert({ e, e });
}
t.InOrder();
cout << t.IsBalance() << endl;
}
// 插入一堆随机值,测试平衡,顺便测试一下高度和性能等
void TestRBTTree2()
{
const int N = 100000;
vector<int> v;
v.reserve(N);
srand((unsigned int)time(0));
for (int i = 0; i < N; i++)
{
v.push_back(rand() + i);
}
size_t begin2 = clock();
RBTree<int, int> t;
for (auto e : v)
{
t.Insert(make_pair(e, e));
}
size_t end2 = clock();
cout << "Insert:" << end2 - begin2 << endl;
cout << t.IsBalance() << endl;
cout << "Height:" << t.Height() << endl;
cout << "Size:" << t.Size() << endl;
size_t begin1 = clock();
// 确定在的值
/*for (auto e : v)
{
t.Find(e);
}*/
// 随机值
for (int i = 0; i < N; i++)
{
t.Find((rand() + i));
}
size_t end1 = clock();
cout << "Find:" << end1 - begin1 << endl;
}