RB-tree(红黑树)
红黑树的规则如下:
1.每个节点不是红色就是黑色
2.根节点为黑色
3.如果节点为红色,那么它的子节点必须为黑色
4.任何一个节点到NULL(树的尾端)的任何路径所包含的黑节点个数相同
简而言之就是每个路径的黑色节点数量相同
新增的节点必须为红,因为增加红色节点所要付出的代价会比黑色的要小很多,如果新增节点为黑色,那么就会打破第四条规则,整棵树都要调整,代价是相当之大的
红黑树节点的定义
enum Colour
{
Red,
Black
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Colour _col;
RBTreeNode()
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
{}
};
红黑树的插入操作
红黑树的插入操作分为几种情况
情况一:
当cur为红、parent为红、grandparent为黑、uncle存在并且为红
操作过程:
将parent和uncle全部染成黑色,grandparent染成红色,然后把cur给grandparent继续向上判断,如果cur的parent依旧为红色,那么就要继续染色,如果cur为_root了,将根节点染成黑色。
具象图:
抽象图:
在抽象图当中,在a或者b子树当中触发了染色机制,然后一路染色上来,一直到cur也染成了红色,cur和p就造成冲突,需要继续染色。
情况二:
当cur为红,p为红,g黑,u不存在/u为黑
操作:
p为g的左孩子,cur为p的左孩子,则进行右单旋转;
相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转
最后p变为黑色,cur和g变为红色
具象图:
当uncle为空的时候
抽象图:
情况三:
当cur和p为红,g为黑,u为黑/不存在
如果parent为grandparent的左儿子,对parent左旋,再对grandparent右旋
如果parent为grandparent的右儿子,对parent右旋,再对grandparent左旋
cur染为黑色,cur和grandparent染为红色。
具象图:
抽象图:
红黑树+测试代码
#pragma once
#include"AVLTree.h"
enum Colour
{
Red,
Black
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
{}
};
template<class K,class V>
class RBTree
{
typedef RBTreeNode<K,V> Node;
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);
cur->_col = Red;
//链接节点
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//检查是否满足红黑树的要求
while (parent && parent->_col == Red)
{
//如果父亲节点的颜色为红色,那么就有可能需要改变颜色或者旋转
Node* grandparent = parent->_parent;
assert(grandparent);
assert(grandparent->_col == Black);//父亲为红色,那么祖父一定为黑色,不然之前的插入就存在问题
if (parent == grandparent->_left)
{
Node* uncle = grandparent->_right;
//情况一,uncle存在并且uncle为红色,就要继续往上染色
if (uncle && uncle->_col == Red)
{
parent->_col = uncle->_col = Black;
grandparent->_col = Red;
cur = grandparent;
parent = cur->_parent;
}
else
{
//uncle不存在或者uncle为黑色就会走到这里
//情况二+情况三
if (cur == parent->_left)
{
// 情况二:右单旋+变色
// g
// p u
// c
//右旋+染色
RotateR(grandparent);
parent->_col = Black;
grandparent->_col = Red;
}
else
{
// 情况三:左右单旋+变色
// g
// p u
// c
RotateL(parent);
RotateR(grandparent);
cur->_col = Black;
parent->_col = grandparent->_col = Red;
}
break;
}
}
else
{
Node* uncle = grandparent->_left;
if (uncle && uncle->_col == Red)
{
parent->_col = uncle->_col = Black;
grandparent->_col = Red;
cur = grandparent;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
RotateL(grandparent);
parent->_col = Black;
grandparent->_col = Red;
}
else
{
RotateR(parent);
RotateL(grandparent);
cur->_col = Black;
grandparent->_col = Red;
}
break;
}
}
}
_root->_col = Black;
return true;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalance()
{
if (_root == nullptr)
{
return true;
}
if (_root->_col == Red)
{
cout << "根节点不是黑色" << endl;
return false;
}
// 黑色节点数量基准值
int benchmark = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == Black)
++benchmark;
cur = cur->_left;
}
return PrevCheck(_root, 0, benchmark);
}
private:
bool PrevCheck(Node* root, int blackNum, int& benchmark)
{
if (root == nullptr)
{
if (blackNum != benchmark)
{
cout << "某条黑色节点的数量不相等" << endl;
return false;
}
else
{
return true;
}
}
if (root->_col == Black)
{
++blackNum;
}
if (root->_col == Red && root->_parent->_col == Red)
{
cout << "存在连续的红色节点" << endl;
return false;
}
return PrevCheck(root->_left, blackNum, benchmark)
&& PrevCheck(root->_right, blackNum, benchmark);
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* pparent = parent->_parent;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;;
}
subR->_parent = pparent;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
Node* pparent = parent->_parent;
//防止空指针
if (subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
//如果parent就是根节点
_root = subL;
subL->_parent = nullptr;
}
else
{
//如果parent只是一颗子树的根节点,就还需要连接好parent
//判断是左还是右节点
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
subL->_parent = pparent;
}
}
Node* _root = nullptr;
};
void TestRBTree2()
{
size_t N = 1000;
srand(time(0));
RBTree<int, int> t1;
for (size_t i = 0; i < N; ++i)
{
int x = rand();
cout << "Insert:" << x << ":" << i << endl;
t1.Insert(make_pair(x, i));
}
cout << "IsBalance:" << t1.IsBalance() << endl;
}
运行结果: