红黑树:为一棵二叉搜索树,树中的每一个结点颜色不是红色就是黑色。
红黑树性质:
证第4条性质:
假设一红黑树任意路径的黑色节点个数为r,由性质2可得,不存在连续两个红色的节点,因此红色节点 后面都会跟随着黑色节点,则从根节点到任一外部节点路径上都有r~2r个节点。故得证。
结论1.设h
为红黑树的高度,n
为树中节点的个数,r
为任一路径的黑色节点个数,则有以下关系:
(1) h ≤ 2r
(2) n ≥ 2^r - 1
(3) h ≤ 2log2(n + 1)
证明:
(1)从根到任一外部节点的路径长度不超过2r
,同时从树的定义可知,树的高度即为根节点的高度,等于从根到离根最远的外部节点的路径的长度,因此有h ≤ 2r
。
(2)红黑树任一路径黑色节点数为r
,则从第1层到第r
层没有外部节点,因而在这些层内共有2^r - 1
个内部节点,也就是说,内部节点的总数至少为2 ^ r - 1
。
(3)由(2)得 r ≤ log2(n + 1)
,则推得,h ≤ 2log2(n + 1)
。
红黑树的最大高度为2log2(n + 1)
,所以插入、搜索、删除的时间复杂度为O(log2(n))
。
使用bst的插入算法将一个元素插入到红黑树中,将该元素作为新的叶节点插入到某一位置,并为该元素进行染色。
cur:当前节点,parent:父节点,grandfather:祖父节点,uncle:叔叔节点
cur为红,parent为红,grandfather为黑,uncle存在且为红。
cur 和 parent 出现连续两个红色节点,则违反了性质3,解决办法:对parent、uncle节点染色为黑,将grandfather染色为红色,此时可能依然会出现两个连续的红色节点,则将cur节点变更为grandfather节点,继续向上更新。
情况1伪代码:
if (uncle && uncle->_color == RED)//uncle节点存在且为红色
{
parent->_color = BLACK;//父节点变为黑色
uncle->_color == BLACK;//叔叔节点变为黑色
grandfather->_color = RED;//祖父节点变为红色
cur = grandfather;//cur变更为当前祖父节点,继续向上更新
parent = cur->_parent;//parent变为当前cur的父节点
}
继续向上更新是因为,当前祖父节点可能是子树,可能为根节点,若为子树,则需要向上更新,若为根节点,则在更新完毕之后,再将根节点置为黑色。
cur为红,parent为红,grandfather为黑,uncle不存在或者uncle为黑。
uncle的两种情况:
解决办法:parent为grandfather的左孩子,cur为parent的左孩子,对grandfather进行右单旋,parent变为黑色,grandfather变为红色。
cur为红,parent为红,grandfather为黑,uncle不存在或者uncle为黑。
这种情况下,主要是cur节点在parent节点右侧。
解决办法:parent为grandfather的左孩子,cur为parent的右孩子,先对parent进行左单旋,交换cur和parent节点,再对grandfather进行右单旋,parent变为黑色,grandfather变为红色。
情况2与情况3伪代码:
if (cur == parent->_right)//cur节点在右侧,先左单旋,转化为情况2
{
RotateLeft(parent);//左单旋
swap(parent, cur);//交换parent和cur节点
}
RotateRight(grandfather);//祖父节点右单旋
grandfather->_color = RED;//祖父颜色变为红色
parent->_color = BLACK;//父节点颜色变为黑色
上述三种情况,全部是在parent节点在祖父节点左侧的情况。
下面讨论,parent节点在祖父节点右侧的情况。
cur为红,parent为红,grandfather为黑,uncle存在且为红。
与情况一类似,解决方法相同。
解决办法:对parent、uncle节点染色为黑,将grandfather染色为红色,此时可能依然会出现两个连续的红色节点,则将cur节点变更为grandfather节点,继续向上更新。
情况4伪代码:
if (uncle && uncle->_color == RED)//uncle节点存在且为红色
{
parent->_color = BLACK;//父节点变为黑色
uncle->_color == BLACK;//叔叔节点变为黑色
grandfather->_color = RED;//祖父节点变为红色
cur = grandfather;//cur变更为当前祖父节点,继续向上更新
parent = cur->_parent;//parent变为当前cur的父节点
}
cur为红,parent为红,grandfather为黑,uncle不存在或者uncle为黑。
cur为parent的右孩子。
解决办法:parent为grandfather的右孩子,cur为parent的右孩子,对grandfather进行左单旋,parent变为黑色,grandfather变为红色。
cur为红,parent为红,grandfather为黑,uncle不存在或者uncle为黑。
cur为parent的左孩子。
解决办法:parent为grandfather的右孩子,cur为parent的左孩子,先对parent进行右单旋,交换cur和parent节点,再对grandfather进行左单旋,parent变为黑色,grandfather变为红色。
情况5与情况6伪代码:
if (cur == parent->_left)//cur节点在左侧,先右单旋,转化为情况5
{
RotateRight(parent);//左单旋
swap(parent, cur);//交换parent和cur节点
}
RotateLeft(grandfather);//祖父节点右单旋
grandfather->_color = RED;//祖父颜色变为红色
parent->_color = BLACK;//父节点颜色变为黑色
#pragma once
#include
using namespace std;
enum Color{
RED, BLACK };
template<class T>
struct RBTreeNode
{
RBTreeNode(const T& x = T(), Color c = RED)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(x)
,_color(c)
{
}
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _color;
};
template<class T>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
RBTree()
{
_head = new Node;
_head->_left = _head;
_head->_right = _head;
_head->_parent = nullptr;
}
~RBTree()
{
Destroy(_head->_parent);
delete _head;
_head = nullptr;
}
bool insert(const T& data)
{
//先找到红黑树的根节点
Node*& root = GetRoot();
if (root == nullptr)//说明红黑树为空
{
root = new Node(data, BLACK);
root->_parent = _head;
_head->_left = root;
_head->_right = root;
_head->_parent = root;
return true;
}
Node* cur = root;
Node* parent = _head;
while (cur)
{
parent = cur;
if (data > cur->_data)
cur = cur->_right;
else if (data < cur->_data)
cur = cur->_left;
else//不插入重复的元素
return false;
}
cur = new Node(data);
cur->_parent = parent;
if (data > parent->_data)
parent->_right = cur;
else
parent->_left = cur;
//检测节点颜色
while (parent != _head && parent->_color == RED)
{
Node* grandfather = parent->_parent;//祖父
if (parent == grandfather->_left)//在左侧
{
Node* uncle = grandfather->_right;//叔叔节点
if (uncle && uncle->_color == RED)//第一种情况
{
parent->_color = BLACK;
uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else//第2 3种情况
{
if (cur == parent->_right)//第三种情况,先左单旋,交换cur 和parent节点
{
RotateLeft(parent);
swap(parent, cur);
}
RotateRight(grandfather);//再对grandfather节点进行右单旋
parent->_color = BLACK;
grandfather->_color = RED;//重新染色
}
}
else//在右侧
{
Node* uncle = grandfather->_left;//叔叔节点
if (uncle && uncle->_color == RED)//第4种情况
{
parent->_color = BLACK;
uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else//第5 6种情况
{
if (cur == parent->_left)//第5种情况,先右单旋,交换cur 和parent节点
{
RotateRight(parent);
swap(parent, cur);
}
RotateLeft(grandfather);//再对grandfather节点进行左单旋
parent->_color = BLACK;
grandfather->_color = RED;//重新染色
}
}
}
root->_color = BLACK;
_head->_left = LeftMost();
_head->_right = RightMost();
return true;
}
void inOrder()
{
_inOrder(GetRoot());
cout << endl;
}
bool isRBTree()
{
Node* root = _head->_parent;
Node* cur = root;
int BLACKCOUNT = 0;
while (cur != nullptr)
{
if (cur->_color == BLACK)
++BLACKCOUNT;
cur = cur->_left;
}
return _isRBTree(root, 0, BLACKCOUNT);
}
private:
bool _isRBTree(Node* root, int PATHBLACKCOUNT, const int& BLACKCOUNT)
{
if (root == nullptr)
return true;
if (root->_color == BLACK)
PATHBLACKCOUNT++;
//性质3
if (root->_left == nullptr && root->_right == nullptr && (PATHBLACKCOUNT != BLACKCOUNT))
{
cout << "违反了性质3" << endl;
return false;
}
//性质2
if (root->_parent != _head && root->_color == RED && root->_parent->_color == RED)
{
cout << "违反了性质2" << endl;
return false;
}
return _isRBTree(root->_left, PATHBLACKCOUNT, BLACKCOUNT) && _isRBTree(root->_right, PATHBLACKCOUNT, BLACKCOUNT);
}
Node*& GetRoot()const
{
return _head->_parent;
}
void Destroy(Node*& root)
{
if (root == nullptr)
return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
root = nullptr;
}
Node* LeftMost()const
{
Node* cur = _head->_parent;
while (cur->_left)
cur = cur->_left;
return cur;
}
Node* RightMost()const
{
Node* cur = _head->_parent;
while (cur->_right)
cur = cur->_right;
return cur;
}
void RotateRight(Node* parent)//右单旋
{
Node* subL = parent->_left;
parent->_left = subL->_right;
if (subL->_right != nullptr)
subL->_right->_parent = parent;
subL->_right = parent;
subL->_parent = parent->_parent;
if (parent->_parent != _head)
{
if (parent == parent->_parent->_left)
parent->_parent->_left = subL;
else
parent->_parent->_right = subL;
}
else
{
parent->_parent->_parent = subL;
}
parent->_parent = subL;
}
void RotateLeft(Node* parent)//左单旋
{
Node* subR = parent->_right;
parent->_right = subR->_left;
subR->_parent = parent->_parent;
if (subR->_left != nullptr)
subR->_left->_parent = parent;
subR->_left = parent;
if (parent->_parent != _head)
{
if (parent == parent->_parent->_left)
parent->_parent->_left = subR;
else
parent->_parent->_right = subR;
}
else
{
parent->_parent->_parent = subR;
}
parent->_parent = subR;
}
void _inOrder(Node* root)const
{
if (root == nullptr)
return;
_inOrder(root->_left);
cout << root->_data << " ";
_inOrder(root->_right);
}
private:
Node* _head;
};