博客主页: 酷酷学!!!
正文开始
红黑树, 是一种二叉搜索树, 但在每个节点上增加一个存储位表示节点的颜色, 可以是Red或者Black. 通过对任何一条从根到叶子的路径上各个节点着色方式的限制, 红黑树确保没有一条路径会比其他路径长出两倍, 因而是接近平衡的.
满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍
enum Color
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
pair<K, V> _kv;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
Color col;
RBTreeNode(const pair<K, V>& kv)
: _kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
{}
};
插入新的节点颜色设置为红色, 因为破坏规则3的代价更大, 所以我们主动破坏规则4.
首先还是按照二叉搜索树的规则进行插入, 只是在二叉搜索树的规则上限制条件.
//插入
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
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;
//进行红黑树规则处理
//
}
检查插入新的节点之后, 红黑树的性质是否遭到破坏
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
那么首先如果, u不存在, 如下图所示
cur只能是新增, 不然之前就已经不是红黑树了, 对此情况我们进行变色, 已经无法满足规则3, 所以此时要进行旋转操作, 图片上的两种情况为左右单旋.旋转之后要把p变黑,g变红,以维持红黑树的性质.
如果是下图这种情况, 则需要进行双旋, 之后再变色.
如果u存在且为黑, 如下图所示, 则只能是由情况1向上调节而来, 不然如果cur为新增之前就已经违反了规则.
此时, 我们只是简单的变色也无法满足红黑色规则, 所以这里需要旋转加变色
当然对于下图这种情况我们还是需要进行双旋,再变色
p在g的左边还是右边我们也要分情况
编写代码:
//插入
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
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* grandfather = parent->_parent;
//如果p在g左边
// g
// p u
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
//情况1:u存在且为红
if (uncle && uncle->col == RED)
{
parent->col = uncle->col = BLACK;
grandfather->col = RED;
//继续向上调整
cur = grandfather;
parent = cur->_parent;
}
else//情况2:u存在为黑或者不存在
{
if (cur == parent->_left)
{
// g
// p u
//c
RotateR(grandfather);
parent->col = BLACK;
grandfather->col = RED;
}
else
{
// g
// p u
// c
RotateL(parent);
RotateR(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
break;//此时就不需要向上调整了
}
}
else//如果p在g的右边
{
// g
//u p
Node* uncle = grandfather->_left;
//情况1:u存在且为红
if (uncle && uncle->col == RED)
{
parent->col = uncle->col = BLACK;
grandfather->col = RED;
//继续向上调整
cur = grandfather;
parent = cur->_parent;
}
else//情况2:u存在为黑或者不存在
{
if (cur == parent->_right)
{
// g
// u p
// c
RotateL(grandfather);
parent->col = BLACK;
grandfather->col = RED;
}
else
{
// g
// u p
// c
RotateR(parent);
RotateL(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
break;//此时就不需要向上调整了
}
}
}
_root->col = BLACK;
return true;
}
红黑树的检测分为两步:
bool IsBalance()
{
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);
}
private:
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->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);
}
void TestRBTree1()
{
RBTree<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, 14 };
for (auto e : a)
{
t.Insert({ e, e });
}
t.InOrder();
cout << t.IsBalance() << endl;
}
//test.cpp
int main()
{
TestRBTree1();
return 0;
}
#pragma once
#include<assert.h>
#include<iostream>
using namespace std;
enum Color
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
pair<K, V> _kv;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
Color 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:
RBTree()
:_root(nullptr)
{}
RBTree(const RBTree<K, V>& t)
{
_root = Copy(t._root);
}
RBTree<K, V>& operator=(RBTree<K, V> t)
{
swap(_root, t._root);
return *this;
}
~RBTree()
{
Destory(_root);
_root = nullptr;
}
//插入
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
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* grandfather = parent->_parent;
//如果p在g左边
// g
// p u
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
//情况1:u存在且为红
if (uncle && uncle->col == RED)
{
parent->col = uncle->col = BLACK;
grandfather->col = RED;
//继续向上调整
cur = grandfather;
parent = cur->_parent;
}
else//情况2:u存在为黑或者不存在
{
if (cur == parent->_left)
{
// g
// p u
//c
RotateR(grandfather);
parent->col = BLACK;
grandfather->col = RED;
}
else
{
// g
// p u
// c
RotateL(parent);
RotateR(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
break;//此时就不需要向上调整了
}
}
else//如果p在g的右边
{
// g
//u p
Node* uncle = grandfather->_left;
//情况1:u存在且为红
if (uncle && uncle->col == RED)
{
parent->col = uncle->col = BLACK;
grandfather->col = RED;
//继续向上调整
cur = grandfather;
parent = cur->_parent;
}
else//情况2:u存在为黑或者不存在
{
if (cur == parent->_right)
{
// g
// u p
// c
RotateL(grandfather);
parent->col = BLACK;
grandfather->col = RED;
}
else
{
// g
// u p
// c
RotateR(parent);
RotateL(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
break;//此时就不需要向上调整了
}
}
}
_root->col = BLACK;
return true;
}
//查找
Node* Find(const pair<K, V>& kv)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalance()
{
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);
}
private:
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->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);
}
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;
parent->_right = subRL;
subR->_left = parent;
if (subRL)
subRL->_parent = parent;
Node* parentParent = parent->_parent;
parent->_parent = subR;
if (parentParent == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
parentParent->_left = subR;
else
parentParent->_right = subR;
subR->_parent = parentParent;
}
}
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* parentParent = parent->_parent;
parent->_parent = subL;
if (parentParent == nullptr)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (parentParent->_left == parent)
parentParent->_left = subL;
else
parentParent->_right = subL;
subL->_parent = parentParent;
}
}
void Destory(Node* root)
{
if (root == nullptr) return;
Destory(root->_left);
Destory(root->_right);
delete root;
}
Node* Copy(Node* root)
{
if (root == nullptr)
return nullptr;
Node* newnode = new Node(root->_kv);
newnode->_left = Copy(root->_left);
newnode->_right = Copy(root->_right);
return newnode;
}
Node* _root = nullptr;
};
void TestRBTree1()
{
RBTree<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, 14 };
for (auto e : a)
{
t.Insert({ e, e });
}
t.InOrder();
cout << t.IsBalance() << endl;
}
红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(
),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。