目录
一、红黑树结点结构
与AVL树相同的使用三叉链表实现,多了一个枚举类型的成员,用来表示每个结点的红黑颜色。
enum Color
{
RED,
BLACK
};
template<class K, class V>
class RBTreeNode
{
public:
std::pair<K, V> _kv;
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Color _col;
RBTreeNode(const std::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;
};
三、红黑树插入
bool Insert(const std::pair<K, V> kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
// 1、迭代遍历寻找插入位置
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
std::cout << "该 [" << cur->_kv.first << "] 结点已经存在,插入失败" << std::endl;
return false;
}
}
// 2、找到插入位置之后,新建结点进行接入
cur = new Node(kv);
cur->_parent = parent;
cur->_col = RED;
if (kv.first > parent->_kv.first)
parent->_right = cur;
else
parent->_left = cur;
// 3、对红黑树进行处理 先看父亲是否为黑色
// 如果父亲为黑色,那么直接插入结束
if (parent && parent->_col == BLACK)
return true;
4、父亲为红色的条件下,看叔叔颜色
// 下来的结果父亲只能是红色,那么根据不红红(父子不能同时为红色)
// 不断的向上更新 父子不能同时为红色 所以使用while
while (parent && parent->_col == RED)
{
// 先看父亲红不红,再看叔叔红不红,
但是要想看叔叔红不红,必须要清楚叔叔在左边还是右边,
因此需要知道爷爷和父亲的关系,才能确定叔叔的位置
Node* grandfather = parent->_parent;
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)
{
叔叔为红色,叔父爷变色,
cur更新为爷爷,让parent更新为爷爷的父亲,
再次进行红黑树判定
uncle->_col = BLACK;
parent->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
旋转+变色之后 需要break跳出循环
// 叔叔为黑色,进行旋转+变色
if (cur == parent->_left)
{
单旋 爷父 变色
对于爷的情况 均为变红
对于父子情况 均为变黑
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
双旋 爷孙 变色
RotateLR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
uncle->_col = BLACK;
parent->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
// 叔叔为黑色,进行旋转+变色
if (cur == parent->_left)
{
RotateRL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
四、旋转代码的实现
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
// 更新subL的父指针,俩种情况
if (parent == _root)
{
subL->_parent = nullptr;
_root = subL;
}
else
{
Node* ppNode = parent->_parent; // 需要找parent的父亲结点
if (parent == ppNode->_left) // 并且判断parent与其父亲的左右关系
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
// 更新subL的右
subL->_right = parent;
// 更新parent的父和左指针
parent->_parent = subL;
parent->_left = subLR;
// 再subLR存在的情况下 更新它的_parent
if (subLR)
{
subLR->_parent = parent;
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
// 更新了subR的_parent指针
if (parent == _root)
{
subR->_parent = nullptr;
_root = subR; // 只有parent为根的时候才更新subR为根
}
else
{
Node* ppNode = parent->_parent;
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
// 更新subR的_left指针
subR->_left = parent;
// 更新parent的父和右
parent->_parent = subR;
parent->_right = subRL;
// 更新suRL
if (subRL)
{
subRL->_parent = parent;
}
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
RotateL(subL);
RotateR(parent);
}
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
RotateR(subR);
RotateL(parent);
}
五、完整源码
#include<iostream>
#include<queue>
#include<vector>
#include<assert.h>
// using namespace std;
enum Color
{
RED,
BLACK
};
template<class K, class V>
class RBTreeNode
{
public:
std::pair<K, V> _kv;
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Color _col;
RBTreeNode(const std::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 std::pair<K, V> kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
// 1、迭代遍历寻找插入位置
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
std::cout << "该 [" << cur->_kv.first << "] 结点已经存在,插入失败" << std::endl;
return false;
}
}
// 2、找到插入位置之后,新建结点进行接入
cur = new Node(kv);
cur->_parent = parent;
cur->_col = RED;
if (kv.first > parent->_kv.first)
parent->_right = cur;
else
parent->_left = cur;
// 3、对红黑树进行处理 先看父亲是否为黑色
// 如果父亲为黑色,那么直接插入结束
if (parent && parent->_col == BLACK)
return true;
// 下来的结果父亲只能是红色,那么根据不红红(父子不能同时为红色)
// 不断的向上更新父子不能同时为红色 所以使用while
while (parent && parent->_col == RED)
{
// 先看父亲红不红,再看叔叔红不红,但是要想看叔叔红不红,必须要清楚叔叔在左边还是右边,因此需要知道爷爷和父亲的关系,才能确定叔叔的位置
Node* grandfather = parent->_parent;
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)
{
// 叔叔为红色,叔父爷变色,爷爷指针更新为cur,让parent更新为cur的父亲,再次进行红黑树判定
uncle->_col = BLACK;
parent->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
// 叔叔为黑色,进行旋转+变色
if (cur == parent->_left)
{
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateLR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
uncle->_col = BLACK;
parent->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
// 叔叔为黑色,进行旋转+变色
if (cur == parent->_left)
{
RotateRL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
// 更新subL的父指针,俩种情况
if (parent == _root)
{
subL->_parent = nullptr;
_root = subL;
}
else
{
Node* ppNode = parent->_parent; // 需要找parent的父亲结点
if (parent == ppNode->_left) // 并且判断parent与其父亲的左右关系
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
// 更新subL的右
subL->_right = parent;
// 更新parent的父和左指针
parent->_parent = subL;
parent->_left = subLR;
// 再subLR存在的情况下 更新它的_parent
if (subLR)
{
subLR->_parent = parent;
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
// 更新了subR的_parent指针
if (parent == _root)
{
subR->_parent = nullptr;
_root = subR; // 只有parent为根的时候才更新subR为根
}
else
{
Node* ppNode = parent->_parent;
if (ppNode->_left == parent)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
// 更新subR的_left指针
subR->_left = parent;
// 更新parent的父和右
parent->_parent = subR;
parent->_right = subRL;
// 更新suRL
if (subRL)
{
subRL->_parent = parent;
}
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
RotateL(subL);
RotateR(parent);
}
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
RotateR(subR);
RotateL(parent);
}
void Print()
{
CX_Print(_root);
}
void CX_Print(Node* parent)
{
std::queue<Node*> q;
std::vector<Node*> res;
q.push(parent);
while (!q.empty())
{
Node* cur = q.front();
res.push_back(cur);
q.pop();
if (cur->_left)
q.push(cur->_left);
if (cur->_right)
q.push(cur->_right);
}
for (Node* key : res)
{
std::cout << key->_kv.first << " ";
}
std::cout << std::endl;
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
// 和二叉排序树类似,不过这里的结点是 const pair<K, V>& _key
// 所以比较的时候使用 cur->_key.first 来访问第一个关键字
if (cur->_kv.first > key)
cur = cur->_left;
else if (cur->_kv.first < key)
cur = cur->_right;
else
return cur;
}
return nullptr;
}
private:
Node* _root = nullptr;
};
void TestAVLTreeL()
{
RBTree<int, int> t;
t.Insert({ 10, 1 });
t.Insert({ 12, 1 });
t.Insert({ 8, 1 });
t.Insert({ 7, 1 });
t.Insert({ 9, 1 });
t.Print();
t.Insert({ 6, 1 });
t.Print();
}
void TestAVLTreeR()
{
RBTree<int, int> t;
t.Insert({ 10, 1 });
t.Print();
t.Insert({ 12, 1 });
t.Print();
t.Insert({ 8, 1 });
t.Print();
t.Insert({ 11, 1 });
t.Insert({ 14, 1 });
t.Print();
t.Insert({ 13, 1 });
t.Print();
}
#if 0
void TestAVLTree1()
{
AVLTree<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 };
for (auto e : a)
{
t.Insert({ e, e });
t.Print();
cout << endl;
}
// t.Insert({14,1}); RL
t.Insert({ 17,1 });
t.Print();
if (t.Is_Balance_Tree())
cout << "is balance" << endl;
else
cout << "no balance" << endl;
}
#endif
void TestAVLTree2()
{
const int N = 10000;
std::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(std::make_pair(e, e));
}
size_t end2 = clock();
std::cout << "Insert:" << end2 - begin2 << std::endl;
t.Print();
/*if (t.Is_Balance_Tree())
std::cout << "is balance" << std::endl;
else
std::cout << "no balance" << std::endl;*/
// std::cout << "Height:" << t.Height() << std::endl;
// cout << "Size:" << t.Size() << endl;
size_t begin1 = clock();
// 确定在的值
for (auto e : v)
{
t.Find(e);
}
// 随机值
/*for (size_t i = 0; i < N; i++)
{
t.Find((rand() + i));
}
size_t end1 = clock();
cout << "Find:" << end1 - begin1 << endl;*/
}
int main()
{
//TestAVLTreeR();
// TestAVLTreeL();
// TestAVLTree1();
TestAVLTree2();
return 0;
}