目录
1.红黑树的结构
2.红黑树的节点
3.红黑树的实现
1)插入操作
1.u存在且为红
2.u不存在或存在且为黑(且cur 为 parent 的左)
3.u不存在或存在且为黑(且cur 为 parent 的右)
2)查找操作
3)判断是否为有效的红黑树
4)逻辑测试
完整代码:
1.红黑树的结构
其是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。
性质:
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
2.红黑树的节点
节点和二叉搜索树几乎一样,只不过多了个表示颜色的存储位
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _data;
color _col;
RBTreeNode(const pair<K, V>& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
3.红黑树的实现
1)插入操作
对于红黑树来说,最重要的依旧是插入操作,与AVL树不同的是,一个是插入完后调整平衡因子,另一个是插入完后调整节点的颜色,使其保持性质
bool Insert(const pair<K, V>& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (data.first < cur->_data.first)
{
parent = cur;
cur = cur->_left;
}
else if (data.first > cur->_data.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(data);
if (parent->_data.first < data.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
// 颜色调整
......
}
关于颜色调整,一共分为三种情况:
但是要从两个大类来分析 -> 即 p 是位于左还是位于右,操作起来是一样的,只不过要分开写
这里我们只从p在左边进行分析,因为两者分析方式一致。
1.u存在且为红
这种是最简单的情况,因为就只需要去变动颜色即可:
p 和 u 变为黑色,g 变为红色
但是要谨记,根节点是一定为黑色的,如果g为根,要将其变为黑色
2.u不存在或存在且为黑(且cur 为 parent 的左)
这时候就不仅仅需要变动颜色,而且还需要进行右旋 -> RotateR(grandfather)
3.u不存在或存在且为黑(且cur 为 parent 的右)
这种情况是三种情况中最难搞的:
需要变动颜色,且需要进行双旋转->即先 RotateL(parent) 然后 RotateR(grandfather)
2)查找操作
与二叉搜索树相同:
Node* Find(const V& value)
{
Node* cur = _root;
while (cur)
{
if (value < cur->_data.first)
{
cur = cur->_left;
}
else if (value > cur->_data.first)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
}
3)判断是否为有效的红黑树
可以先记录最左边一条路的黑色节点个数,然后去递归每一条路,拿到每一条路径的上的黑色节点与其进行比较,若不相同,则返回false,递归同时,检查该节点是否与其父节点同时为红色,若为,则也返回false
bool IsValid()
{
Node* cur = _root;
size_t comp = 0;
while (cur)
{
if (cur->_col == BLACK)
comp++;
cur = cur->_left;
}
return _IsValid(_root, 0, comp);
}
bool _IsValid(Node* root, size_t dist, size_t comp)
{
if (root == nullptr)
{
if (dist != comp)
{
cout << "存在黑色节点不相等的两条路" << endl;
return false;
}
return true;
}
if (root->_col == BLACK)
dist++;
if (root->_col == RED && root->_parent->_col == RED)
{
cout << "有两个连续的红色节点->数字" << root->_data.first << endl;
return false;
}
return _IsValid(root->_left, dist, comp) && _IsValid(root->_right, dist, comp);
}
这时,基本逻辑就已经都实现完了,可以进行测试了
4)逻辑测试
void TestRBTree1()
{
//int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14, 8, 3, 1, 10, 6, 4, 7, 14, 13 };
RBTree<int, int> t1;
for (auto e : a)
{
if (e == 8)
int i = 0;
t1.Insert({ e,e });
cout << "Insert:" << e << "->" << t1.IsValid() << endl;
}
t1.InOrder();
}
经测试,发现插入每个数据后都平衡,因此没问题
不过,还有项更严谨的测试,即产生大量随机数,插入进去测试平衡:
void TestRBTree2()
{
const int N = 1000000;
vector<int> v;
v.reserve(N);
srand(time(0));
for (size_t 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 << t.IsValid() << endl;
}
最后显示的结果也是平衡,那就大概率没有逻辑上的问题了
完整代码:
#pragma once
#include <iostream>
#include <vector>
enum color
{
BLACK,
RED
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _data;
color _col;
RBTreeNode(const pair<K, V>& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
template<class K, class V>
class RBTree
{
public:
typedef RBTreeNode<K, V> Node;
public:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* ppNode = parent->_parent;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subL;
}
else
{
ppNode->_right = subL;
}
subL->_parent = ppNode;
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* ppNode = parent->_parent;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (ppNode->_right == parent)
{
ppNode->_right = subR;
}
else
{
ppNode->_left = subR;
}
subR->_parent = ppNode;
}
}
bool Insert(const pair<K, V>& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (data.first < cur->_data.first)
{
parent = cur;
cur = cur->_left;
}
else if (data.first > cur->_data.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(data);
if (parent->_data.first < data.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
// 改颜色
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// cur为红,p为红,g为黑,u存在且为红
if (uncle && uncle->_col == RED)
{
// g
// p u
// c
grandfather->_col = RED;
parent->_col = uncle->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
else if (!uncle || (uncle && uncle->_col == BLACK)) // cur为红,p为红,g为黑,u不存在或存在且为黑
{
if (cur == parent->_left)
{
// g p
// p u -> c g
// c u
grandfather->_col = RED;
parent->_col = BLACK;
RotateR(grandfather);
}
else
{
// g g g
// p u -> c u (变成上述情况去解决) -> p u
// c p c
grandfather->_col = RED;
cur->_col = BLACK;
RotateL(parent);
RotateR(grandfather);
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
// g
// u p
// c
grandfather->_col = RED;
parent->_col = uncle->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
else if (!uncle || (uncle && uncle->_col == BLACK))
{
if (cur == parent->_right)
{
// g p
// u p -> g c
// c u
grandfather->_col = RED;
parent->_col = BLACK;
RotateL(grandfather);
}
else
{
// g g
// u p -> u p (变成上述情况去解决)
// c c
grandfather->_col = RED;
cur->_col = BLACK;
RotateR(parent);
RotateL(grandfather);
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
Node* Find(const V& value)
{
Node* cur = _root;
while (cur)
{
if (value < cur->_data.first)
{
cur = cur->_left;
}
else if (value > cur->_data.first)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
}
// 获取红黑树最左侧节点
Node* LeftMost()
{
Node* cur = _root;
while (cur->_left)
{
cur = cur->_left;
}
return cur;
}
// 获取红黑树最右侧节点
Node* RightMost()
{
Node* cur = _root;
while (cur->_right)
{
cur = cur->_right;
}
return cur;
}
// 遍历 打印
void InOrder()
{
_InOrder(_root);
cout << endl;
}
// 判断是否为有效红黑树
bool IsValid()
{
Node* cur = _root;
size_t comp = 0;
while (cur)
{
if (cur->_col == BLACK)
comp++;
cur = cur->_left;
}
return _IsValid(_root, 0, comp);
}
private:
bool _IsValid(Node* root, size_t dist, size_t comp)
{
if (root == nullptr)
{
if (dist != comp)
{
cout << "存在黑色节点不相等的两条路" << endl;
return false;
}
return true;
}
if (root->_col == BLACK)
dist++;
if (root->_col == RED && root->_parent->_col == RED)
{
cout << "有两个连续的红色节点->数字" << root->_data.first << endl;
return false;
}
return _IsValid(root->_left, dist, comp) && _IsValid(root->_right, dist, comp);
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_data.first << ":" << root->_data.second << endl;
_InOrder(root->_right);
}
private:
Node* _root = nullptr;
};
void TestRBTree1()
{
//int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14, 8, 3, 1, 10, 6, 4, 7, 14, 13 };
RBTree<int, int> t1;
for (auto e : a)
{
if (e == 8)
int i = 0;
t1.Insert({ e,e });
cout << "Insert:" << e << "->" << t1.IsValid() << endl;
}
t1.InOrder();
}
void TestRBTree2()
{
const int N = 1000000;
vector<int> v;
v.reserve(N);
srand(time(0));
for (size_t i = 0; i < N; i++)
{
v.push_back(rand() + i);
//cout << v.back() << endl;
}
size_t begin2 = clock();
RBTree<int, int> t;
for (auto e : v)
{
t.Insert(make_pair(e, e));
//cout << "Insert:" << e << "->" << t.IsBalance() << endl;
}
size_t end2 = clock();
cout << t.IsValid() << endl;
}