目录
1.红黑树的概念
红黑树是一棵⼆叉搜索树,名字的"红""黑"是说,他的每个结点用⼀个存储位来表⽰结点的颜⾊,可以是红⾊或者⿊⾊
通过对任何⼀条从根到叶⼦的路径上各个结点的颜⾊进⾏约束,红⿊树确保没有⼀条路径会⽐其他路 径⻓出2倍,因⽽是接近平衡的

2.红黑树的规则
- 每个节点只能为红色或黑色
- 根节点必须为黑色
- 任意一个节点,从该节点到其所有的NULL节点的简单路径上,都包含相同数量的黑色节点
- 如果一个节点是红色的,它的两孩子个节点必须是黑色的
依据第四条规则,不难发现,红黑树中不能出现连续的红节点
在一些书上也会将"叶子节点"(走到空的位置)画出,方便标识所有的路径

依据红黑树的规则 可以保证从根节点出发,最长路径不超过最短路径的2倍
因为从黑色的根节点出发,每条路径上的黑色节点数量相同(规则3),而红色节点不可以连续出现(规则4),所以,最短 路径是全黑 ,最长 路径是一黑一红

3.红黑树的效率
节点数量为N的红黑树,h为最短路径,则2h为最长路径,查找的次数为红黑树的高度次
N
,则 h
注:以一颗最低节点的满二叉树计算,总节点为
以一颗最高节点的满二叉树计算,总节点为
4.红黑树的实现
红黑树的节点
红黑树节点的颜色不是红色就是黑色,因此可以使用枚举描述其颜色
// 枚举值表⽰颜⾊
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)
{}
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
private:
Node* _root = nullptr;
};
红黑树的插入
红黑树插入一个值的过程
- 插⼊⼀个值按⼆叉搜索树规则进⾏插⼊(左根右),插⼊后我们只需要观察是否符合红⿊树的4条规则
- 如果是空树插⼊,新增结点是⿊⾊结点。如果是⾮空树插⼊,新增结点必须红⾊结点,因为⾮空树 插⼊,新增⿊⾊结点就破坏了规则4,规则4是很难维护的
- ⾮空树插⼊后,新增结点必须红⾊结点,如果⽗亲结点是⿊⾊的,则没有违反任何规则,插⼊结束
- ⾮空树插⼊后,新增结点必须红⾊结点,如果⽗亲结点是红⾊的,则违反规则3。进⼀步分析,c是 红⾊,p为红,g必为⿊,这三个颜⾊都固定了,关键的变化看u的情况,需要根据u分为以下⼏种情况分别处理
下图中假设我们把新增结点标识为c(cur),c的⽗亲标识为p(parent),p的⽗亲标识为 g(grandgather),p的兄弟标识为u
情况1.变色,继续向上处理
c为红,p为红,g为⿊,u存在且为红,则将p和u变⿊,g变红
p是必须要变黑的,因为红色节点不能连续出现
为什么不把c变黑?因为c变黑和插入黑色节点无异,而黑色节点的插入会导致黑色节点的数量难以平衡
p与u这两条路径都经过了g节点,将g变红,p和u变黑,既确保了红色节点不连续出现,又保证了每条路径上的黑色节点的数量相同,符合红黑树的规则
cpp
if (uncle && uncle->_col == RED)
{
//u存在且为红,变色
parent->_col = uncle->_col = BLACK;
grand->_col = RED;
cur = grand;
parent = cur->_parent;
}

镜像的这种情况一样用这个方法处理,都是将p与u变黑,g变红
单纯改变颜色需要继续向上处理,因为改变了与祖先节点连接的节点的颜色(g节点由黑变红),可能会出现连续的红色节点,所以需要继续向上处理
情况2:单旋+变色
c为红,p为红,g为⿊,u不存在或者u存在且为⿊。u不存在,则c⼀定是新增结点,;u存在且为⿊则c一定不是新增,c之前是黑色的,是在c的子树中插入,符合情况1,变⾊将c从⿊⾊变成红⾊,更新上来的

这里的单旋与AVL树的单旋几乎一模一样,具体可以参考我的这篇博客:
右单旋+变色
cpp
//u存在且为黑,或不存在
//单旋+变色
if (cur == parent->_left)
{
// g
// p u
//c
RotateR(grand);
parent->_col = BLACK;
grand->_col = RED;
}
这种情况下p一定要变黑,但是单纯变黑会导致黑色节点数量异常,为了保证黑色节点的数量符合规则,需要进行旋转,与之镜像的情况则进行相反方向的旋转,再变色处理
左单旋+变色
cpp
// g
// u p
// c
RotateL(grand);
parent->_col = BLACK;
grand->_col = RED;

情况3:双旋+变色
c为红,p为红,g为⿊,u不存在或者u存在且为⿊,u不存在,则c⼀定是新增结点,u存在且为⿊,则 c⼀定不是新增,c之前是⿊⾊的,是在c的⼦树中插⼊,符合情况1,变⾊将c从⿊⾊变成红⾊,更新上 来的
分析:p必须变⿊,才能解决,连续红⾊结点的问题,u不存在或者是⿊⾊的,这⾥单纯的变⾊⽆法解 决问题,需要旋转+变⾊

与AVL树中的双旋一样,这种带有折线的情况需要使用两次单旋来处理,即双旋
左右双旋+变色

cpp
// g
// p u
// c
RotateL(parent);
RotateR(grand);
cur->_col = BLACK;
grand->_col = RED;
右左双旋+变色

cpp
// g
// u p
// c
RotateR(parent);
RotateL(grand);
cur->_col = BLACK;
grand->_col = RED;
红黑树的删除:
红黑树的删除比较复杂,这里不做讲解,请参考其他文献
5.源码
包含红黑树的实现,遍历,以及测试,可直接运行
cpp
#pragma once
#include<iostream>
#include <utility>
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)
{}
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv)
{
if (nullptr == _root)
{
//根节点为空
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
else
{
//根节点不为空
//寻找插入位置
Node* cur = _root;
Node* parent = nullptr;
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);
cur->_col = RED;
//调整指针指向
if (cur->_kv.first < parent->_kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//向上调整
while (parent && parent->_col == RED)
{
Node* grand = parent->_parent;
if (parent == grand->_left)
{
Node* uncle = grand->_right;
if (uncle && uncle->_col == RED)
{
//u存在且为红,变色
parent->_col = uncle->_col = BLACK;
grand->_col = RED;
cur = grand;
parent = cur->_parent;
}
else
{
//u存在且为黑,或不存在
//单旋+变色
if (cur == parent->_left)
{
// g
// p u
//c
RotateR(grand);
parent->_col = BLACK;
grand->_col = RED;
}
else
{
// g
// p u
// c
RotateL(parent);
RotateR(grand);
cur->_col = BLACK;
grand->_col = RED;
}
//经过旋转处理并没有将所连的旋转体的节点变色
//无需向上处理
break;
}
}
else
{
Node* uncle = grand->_left;
if (uncle && uncle->_col == RED)
{
//u存在且为红,变色
parent->_col = uncle->_col = BLACK;
grand->_col = RED;
cur = grand;
parent = cur->_parent;
}
else
{
//u不存在或存在且为黑
if (cur == parent->_left)
{
// g
// u p
// c
RotateR(parent);
RotateL(grand);
cur->_col = BLACK;
grand->_col = RED;
}
else
{
// g
// u p
// c
RotateL(grand);
parent->_col = BLACK;
grand->_col = RED;
}
//经过旋转处理并没有将所连的旋转体的节点变色
//无需向上处理
break;
}
}
}
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << " ";
_InOrder(root->_right);
}
// 前序递归遍历
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 && 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 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);
}
void RotateR(Node* parent)
{
Node* pParent = parent->_parent;
Node* NodeL = parent->_left;
Node* NodeLR = NodeL->_right;
//修正向下关系
NodeL->_right = parent;
parent->_left = NodeLR;
//修正向上关系
parent->_parent = NodeL;
if (NodeLR)
{
NodeLR->_parent = parent;
}
//修正外部关系
if (pParent)
{
NodeL->_parent = pParent;
if (parent == pParent->_left)
{
pParent->_left = NodeL;
}
else
{
pParent->_right = NodeL;
}
}
else
{
_root = NodeL;
NodeL->_parent = nullptr;
}
}
void RotateL(Node* parent)
{
Node* pParent = parent->_parent;
Node* NodeR = parent->_right;
Node* NodeRL = NodeR->_left;
//修正向下关系
parent->_right = NodeRL;
NodeR->_left = parent;
//修正向上关系
parent->_parent = NodeR;
if (NodeRL)
{
NodeRL->_parent = parent;
}
//修正外部关系
if (pParent)
{
NodeR->_parent = pParent;
if (parent == pParent->_left)
{
pParent->_left = NodeR;
}
else
{
pParent->_right = NodeR;
}
}
else
{
_root = NodeR;
NodeR->_parent = nullptr;
}
}
void display()
{
_display(_root);
}
void _display(Node* root)
{
if (nullptr == root)
{
return;
}
_display(root->_left);
cout << root->_kv.first << " ";
_display(root->_right);
}
private:
Node* _root = nullptr;
};
void test()
{
RBTree<int, int> rb;
//变色
//int arr[] = { 2,1,3,4 };
//单旋
//int arr[] = { 1,2,3 };
//双旋
//int arr[] = { 1,3,2 };
pair<int, int> p1{ 2,1 }, p2{ 1,1 }, p3{ 3,1 }, p4{ 4,1 };
rb.Insert(p2);
rb.Insert(p3);
rb.Insert(p1);
//rb.Insert(p4);
rb.display();
}
int main()
{
test();
return 0;
}