红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
每个结点不是红色就是黑色
根节点是黑色的
红色的
,则它的两个孩子结点是黑色的
均包含相同数目的黑色结点
分三个步骤
1.按二叉搜索树的规则插入数据
2.更新整体节点的颜色
3.更新颜色的过程中判断是否需要旋转
bool Insert(const pair<K, V>& kv)
{
Node* parent = nullptr;
Node* cur = _root;
//如果根为空
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
//寻找插入位置
while (cur)
{
//如果要插入的值比cur的值小
if (cur->_kv.first > kv.first)
{
//往左找
parent = cur;
cur = cur->_left;
}
//如果要插入的值比cur的值大
else if (cur->_kv.first < kv.first)
{
//往右找
parent = cur;
cur = cur->_right;
}
//如果相等就不再插入
else
{
return false;
}
}
//插入
cur = new Node(kv);
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
}
因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何 性质,则不需要调整
;但当新插入节点的双亲节点
颜色为红色
时,就违反了性质三
不能有连
在一起的红色节点,此时需要对红黑树分情况来讨论
:
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
情况一:cur为红,p为红,g为黑,u存在且为红
解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
如果向上更新的过程中,parent节点为黑或者已经更新到了根节点
说明子树已经满足了红黑树的规则就停止更新,否则继续向上更新。
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
代码只展示了一次更新的结果,会在while循环不断往上更新直到满足红黑树的规则
。
情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑
小情况1:u不存在
小情况2:u存在且为黑
由上面的情况一向上调整的过程中变成的
解决方法:
p为g的左孩子,cur为p的左孩子,则进行右单旋转;
相反p为g的右孩子,cur为p的右孩子,则进行左单旋转
p、g变色--p变黑,g变红
右旋
//单旋
if (parent->_left == cur)
{
RotateR(grandpa);
parent->_col = BLACK;
grandpa->_col = RED;
}
左旋
//单旋
if (parent->_right == cur)
{
RotateL(grandpa);
parent->_col = BLACK;
grandpa->_col = RED;
}
情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑
小情况1:u不存在
小情况2:u存在且为黑
由上面的情况一向上调整的过程中变成的
解决方法:
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;
相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
则转换成了情况二,然后再由情况二进行旋转调整变成符合规则的红黑树
说明进行了两次旋转:右左双旋或者左右双旋
左右双旋
//双旋
else
{
RotateLR(grandpa);
grandpa->_col = RED;
cur->_col = BLACK;
}
右左双旋
//双旋
else
{
RotateRL(grandpa);
cur->_col = BLACK;
grandpa->_col = RED;
}
bool Insert(const pair<K, V>& kv)
{
Node* parent = nullptr;
Node* cur = _root;
//如果根为空
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
//寻找插入位置
while (cur)
{
//如果要插入的值比cur的值小
if (cur->_kv.first > kv.first)
{
//往左找
parent = cur;
cur = cur->_left;
}
//如果要插入的值比cur的值大
else if (cur->_kv.first < kv.first)
{
//往右找
parent = cur;
cur = cur->_right;
}
//如果相等就不再插入
else
{
return false;
}
}
//插入
cur = new Node(kv);
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
//更新颜色
while (parent && parent->_col == RED)
{
Node* grandpa = parent->_parent;
Node* uncle = nullptr;
if (grandpa->_left == parent)
{
uncle = grandpa->_right;
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
else
{
//单旋
if (parent->_left == cur)
{
RotateR(grandpa);
parent->_col = BLACK;
grandpa->_col = RED;
}
//双旋
else
{
RotateLR(grandpa);
grandpa->_col = RED;
cur->_col = BLACK;
}
break;
}
}
else
{
uncle = grandpa->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
else
{
//单旋
if (parent->_right == cur)
{
RotateL(grandpa);
parent->_col = BLACK;
grandpa->_col = RED;
}
//双旋
else
{
RotateRL(grandpa);
cur->_col = BLACK;
grandpa->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
这边的旋转方法和我之前的博客AVL树里面的旋转方法一样,便不再过多叙述,主要放代码
void RotateR(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的左孩子
Node* subL = parent->_left;
//要调整的节点的左孩子的右孩子
Node* subLR = subL->_right;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subLR)
subLR->_parent = sub;
sub->_left = subLR;
sub->_parent = subL;
subL->_right = sub;
subL->_parent = subparent;
if (_root == sub)
{
_root = subL;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subL;
}
else
{
subparent->_right = subL;
}
}
}
void RotateL(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的右孩子
Node* subR = parent->_right;
//要调整的节点的有孩子的左孩子
Node* subRL = subR->_left;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subRL)
subRL->_parent = sub;
sub->_right = subRL;
sub->_parent = subR;
subR->_left = sub;
subR->_parent = subparent;
if (_root == sub)
{
_root = subR;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subR;
}
else
{
subparent->_right = subR;
}
}
}
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
#pragma once
namespace lzf
{
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;//该节点要存储的值
int _col;//该节点的颜色(新创建的节点默认为红色)
//构造函数
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _col(RED)//新创建的节点默认为红色
{}
};
template<class K,class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_root(nullptr)
{}
bool Insert(const pair<K, V>& kv)
{
Node* parent = nullptr;
Node* cur = _root;
//如果根为空
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
//寻找插入位置
while (cur)
{
//如果要插入的值比cur的值小
if (cur->_kv.first > kv.first)
{
//往左找
parent = cur;
cur = cur->_left;
}
//如果要插入的值比cur的值大
else if (cur->_kv.first < kv.first)
{
//往右找
parent = cur;
cur = cur->_right;
}
//如果相等就不再插入
else
{
return false;
}
}
//插入
cur = new Node(kv);
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
//更新颜色
while (parent && parent->_col == RED)
{
Node* grandpa = parent->_parent;
Node* uncle = nullptr;
if (grandpa->_left == parent)
{
uncle = grandpa->_right;
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
else
{
//单旋
if (parent->_left == cur)
{
RotateR(grandpa);
parent->_col = BLACK;
grandpa->_col = RED;
}
//双旋
else
{
RotateLR(grandpa);
grandpa->_col = RED;
cur->_col = BLACK;
}
break;
}
}
else
{
uncle = grandpa->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
else
{
//单旋
if (parent->_right == cur)
{
RotateL(grandpa);
parent->_col = BLACK;
grandpa->_col = RED;
}
//双旋
else
{
RotateRL(grandpa);
cur->_col = BLACK;
grandpa->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
void InOrder()
{
_InOrder(_root);
}
bool IsRBTree()
{
if (_root&& _root->_col == RED)
{
return false;
}
int blackmark = 0;
Node* left = _root;
while (left)
{
if (left->_col == BLACK)
{
blackmark++;
}
left = left->_left;
}
int blacknum = 0;
return _IsRBTree(_root, blackmark, blacknum);
}
private:
void RotateR(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的左孩子
Node* subL = parent->_left;
//要调整的节点的左孩子的右孩子
Node* subLR = subL->_right;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subLR)
subLR->_parent = sub;
sub->_left = subLR;
sub->_parent = subL;
subL->_right = sub;
subL->_parent = subparent;
if (_root == sub)
{
_root = subL;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subL;
}
else
{
subparent->_right = subL;
}
}
}
void RotateL(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的右孩子
Node* subR = parent->_right;
//要调整的节点的有孩子的左孩子
Node* subRL = subR->_left;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subRL)
subRL->_parent = sub;
sub->_right = subRL;
sub->_parent = subR;
subR->_left = sub;
subR->_parent = subparent;
if (_root == sub)
{
_root = subR;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subR;
}
else
{
subparent->_right = subR;
}
}
}
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
bool _IsRBTree(Node* root, int blackmark, int blacknum)
{
if (root == nullptr)
{
if (blackmark != blacknum)
{
return false;
}
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
return false;
}
if (root->_col == BLACK)
{
blacknum++;
}
return _IsRBTree(root->_left, blackmark, blacknum)
&& _IsRBTree(root->_right, blackmark, blacknum);
}
private:
Node* _root;
};
void Test_RBTree()
{
RBTree<int, int> tree;
tree.Insert(make_pair(5, 5));
tree.Insert(make_pair(3, 3));
tree.Insert(make_pair(8, 8));
tree.Insert(make_pair(4, 4));
tree.Insert(make_pair(6, 6));
tree.Insert(make_pair(2, 2));
tree.Insert(make_pair(7, 7));
tree.InOrder();
cout << tree.IsRBTree();
}
void Test_RBTree2()
{
RBTree<int, int> t;
int a[] = {5,4,3,2,1,0};
//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(make_pair(e, e));
cout << "Insert" << e << ":" << t.IsRBTree() << endl;
}
t.InOrder();
cout << t.IsRBTree() << endl;
}
void TestRBTree()
{
RBTree<int, int> t;
vector<int> v;
srand(time(0));
int N = 10000;
for (int i = 0; i < N; ++i)
{
//v.push_back(rand());
v.push_back(i);
}
//int a[] = {5,4,3,2,1,0};
//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 : v)
{
t.Insert(make_pair(e, e));
if (!t.IsRBTree())
{
cout << "Insert" << e << endl;
}
}
//t.InOrder();
cout << t.IsRBTree() << endl;
/*cout << "高度:" << t.IsRBTree() << endl;*/
}
}