一、概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。
性质:
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
二、红黑树的结点定义
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(T data = T())
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_col(RED)
};
二、红黑树的插入
1、插入结点
Node* root = GetRoot();
if (root == nullptr)
{
root = new Node(data);
root->_parent = _head;
_head->_parent = root;
return true;
}
Node* cur = root;
Node* parent = root;
//找到data节点插入的位置
while (cur)
{
if (data < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (data > cur->_data)
{
parent = cur;
cur = cur->_right;
}
}
//插入data节点
cur = new Node(data);
if (data < parent->_data)
{
cur->_parent = parent;
parent->_left = cur;
}
else
{
cur->_parent = parent;
parent->_right = cur;
}
若插入结点的父亲为黑色,则结束。
若插入结点的父亲为红色,则出现了连续的红色结点,违反规则,需要处理。
2、调整
如插入结点后,该树违反了红黑树的规则,则对其进行调整。
(1)cur红,parent红,gparent黑,uncle存在且红
可以看出,该结点插入后,违反了规则: 如果一个节点是红色的,则它的两个孩子结点是黑色的。
此时,需要对其进行变色:将parent、uncle改为黑,gparent改为红,然后将gparent赋值给cur,若此时cur的父结点为红,则继续向上调整。
(2)cur红,parent红,gparent黑,uncle不存在
此时cur一定是新插入的结点。否则不符合红黑树的规则:不能出现连在一起的红色结点。调整后:
(3)cur红,parent红,gparent黑,uncle存在且为黑
(1)基础情况
此时cur一定不是新增结点,cur一定是由黑色变为红色的,否则就违反了红黑树的规则:每条路径黑色结点相同。
cur变红前的一种可能情况:
注:c:包含一个黑色结点的红黑树 (4种)
d/e:null或一个红色结点(4种)
调整后(旋转+变色):
我们将parent变为黑色,而非将cur变为黑色(即parent为红,cur和gparent为黑),是因为如果parent为红,那么当parent不是根结点的时候,仍需向上处理,即parent为红非终结态。
(2)单旋后转变为基础情况
对于这种情况,我们需要做以下处理:
若parent为gparent的左孩子,cur为parent的右孩子,则针对parent做左单旋转;
若parent为gparent的右孩子,cur为parent的左孩子,则针对parent做右单旋转。
旋转完成后,即转变为基础情况:
3、插入完整代码
bool Insert(const T& data)
{
Node* root = GetRoot();
if (root == nullptr)
{
root = new Node(data);
root->_parent = _head;
_head->_left = root;
_head->_right = root;
_head->_parent = root;
root->_col = BLACK;
return true;
}
Node* cur = root;
Node* parent = root;
//找到data节点插入的位置
while (cur)
{
if (data < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (data > cur->_data)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
//插入data节点
cur = new Node(data);
if (data < parent->_data)
{
cur->_parent = parent;
parent->_left = cur;
}
else
{
cur->_parent = parent;
parent->_right = cur;
}
//更新_head结点链接关系
T min = _head->_left->_data;
T max = _head->_right->_data;
if (data < min)
{
_head->_left = cur;
}
if (data > max)
{
_head->_right = cur;
}
//调整
while (parent && parent->_col == RED)
{
Node* gparent = parent->_parent;
if (parent == gparent->_left)
{
Node* uncle = gparent->_right;
//cur红,parent红,gparent黑,uncle存在且红
if (uncle && uncle->_col == RED)
{
//调整颜色
parent->_col = uncle->_col = BLACK;
gparent->_col = RED;
//继续向上处理
cur = gparent;
parent = cur->_parent;
}
else if(uncle == nullptr)
{
//cur红,parent红,gparent黑,uncle不存在
if (cur == parent->_left)
{
//右旋
RotateR(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
RotateL(parent);
RotateR(gparent);
//变色
cur->_col = BLACK;
parent->_col = gparent->_col = RED;
}
}
else if (uncle && uncle->_col == BLACK)
{
//cur红,parent红,gparent黑,uncle存在且为黑
if (cur == parent->_left)
{
RotateR(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
//对parent左单旋后转变为上面的情况
RotateL(parent);
RotateR(gparent);
//变色
cur->_col = BLACK;
gparent->_col = RED;
}
}
}
else if(parent = gparent->_right)
{
Node* uncle = gparent->_left;
//cur红,parent红,gparent黑,uncle存在且红
if (uncle && uncle->_col == RED)
{
//调整颜色
parent->_col = uncle->_col = BLACK;
gparent->_col = RED;
//继续向上处理
cur = gparent;
parent = cur->_parent;
}
else if (uncle == nullptr)
{
//cur红,parent红,gparent黑,uncle不存在
if (cur == parent->_right)
{
//左旋
RotateL(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
RotateR(parent);
RotateL(gparent);
//变色
cur->_col = BLACK;
parent->_col = gparent->_col = RED;
}
}
else if (uncle && uncle->_col == BLACK)
{
//cur红,parent红,gparent黑,uncle存在且为黑
if (cur == parent->_right)
{
RotateL(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
//对parent右单旋后转变为上面的情况
RotateR(parent);
RotateL(gparent);
//变色
cur->_col = BLACK;
gparent->_col = RED;
}
}
}
}
_head->_parent->_col = BLACK;
return true;
}
三、验证是否为红黑树
验证是否为红黑树,则需要根据红黑树的规则来确定:
没有两个连续的红色结点;
每条路径包含相同的黑色结点。
bool IsValidRBTRee()
{
Node* root = GetRoot();
if (root->_col == RED)
{
return false;
}
if (root == nullptr)
{
return true;
}
int blackc = GetBlackCount(GetRoot());
int blacknum = 0;
_IsValidRBTRee(GetRoot(), blackc, blacknum);
}
bool _IsValidRBTRee(Node* root, size_t blackCount, size_t pathBlack)
{
if (root == nullptr)
{
pathBlack++;
if (pathBlack != blackCount)
{
cout << "各路径黑色结点数量不同" << endl;
return false;
}
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
return false;
}
if (root->_col == BLACK)
{
pathBlack++;
}
return _IsValidRBTRee(root->_left, blackCount, pathBlack)
&& _IsValidRBTRee(root->_right, blackCount, pathBlack);
}
四、完整代码
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(T data = T())
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_col(RED)
{}
};
// 请模拟实现红黑树的插入--注意:为了后序封装map和set,本文在实现时给红黑树多增加了一个头结点
template<class T>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
RBTree()
{
_head = new Node;
_head->_left = _head;
_head->_right = _head;
_head->_parent = _head;
}
// 在红黑树中插入值为data的节点,插入成功返回true,否则返回false
// 注意:为了简单起见,本次实现红黑树不存储重复性元素
bool Insert(const T& data)
{
Node* root = GetRoot();
if (root == nullptr)
{
root = new Node(data);
root->_parent = _head;
_head->_left = root;
_head->_right = root;
_head->_parent = root;
root->_col = BLACK;
return true;
}
Node* cur = root;
Node* parent = root;
//找到data节点插入的位置
while (cur)
{
if (data < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (data > cur->_data)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
//插入data节点
cur = new Node(data);
if (data < parent->_data)
{
cur->_parent = parent;
parent->_left = cur;
}
else
{
cur->_parent = parent;
parent->_right = cur;
}
//更新_head结点链接关系
T min = _head->_left->_data;
T max = _head->_right->_data;
if (data < min)
{
_head->_left = cur;
}
if (data > max)
{
_head->_right = cur;
}
//调整
while (parent && parent->_col == RED)
{
Node* gparent = parent->_parent;
if (parent == gparent->_left)
{
Node* uncle = gparent->_right;
//cur红,parent红,gparent黑,uncle存在且红
if (uncle && uncle->_col == RED)
{
//调整颜色
parent->_col = uncle->_col = BLACK;
gparent->_col = RED;
//继续向上处理
cur = gparent;
parent = cur->_parent;
}
else if(uncle == nullptr)
{
//cur红,parent红,gparent黑,uncle不存在
if (cur == parent->_left)
{
//右旋
RotateR(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
RotateL(parent);
RotateR(gparent);
//变色
cur->_col = BLACK;
parent->_col = gparent->_col = RED;
}
}
else if (uncle && uncle->_col == BLACK)
{
//cur红,parent红,gparent黑,uncle存在且为黑
if (cur == parent->_left)
{
RotateR(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
//对parent左单旋后转变为上面的情况
RotateL(parent);
RotateR(gparent);
//变色
cur->_col = BLACK;
gparent->_col = RED;
}
}
}
else if(parent = gparent->_right)
{
Node* uncle = gparent->_left;
//cur红,parent红,gparent黑,uncle存在且红
if (uncle && uncle->_col == RED)
{
//调整颜色
parent->_col = uncle->_col = BLACK;
gparent->_col = RED;
//继续向上处理
cur = gparent;
parent = cur->_parent;
}
else if (uncle == nullptr)
{
//cur红,parent红,gparent黑,uncle不存在
if (cur == parent->_right)
{
//左旋
RotateL(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
RotateR(parent);
RotateL(gparent);
//变色
cur->_col = BLACK;
parent->_col = gparent->_col = RED;
}
}
else if (uncle && uncle->_col == BLACK)
{
//cur红,parent红,gparent黑,uncle存在且为黑
if (cur == parent->_right)
{
RotateL(gparent);
//变色
parent->_col = BLACK;
gparent->_col = RED;
}
else
{
//对parent右单旋后转变为上面的情况
RotateR(parent);
RotateL(gparent);
//变色
cur->_col = BLACK;
gparent->_col = RED;
}
}
}
}
_head->_parent->_col = BLACK;
return true;
}
// 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
Node* Find(const T& data)
{
Node* cur = GetRoot();
Node* parent = cur;
while (cur)
{
if (data > cur->_data)
{
parent = cur;
cur = cur->_right;
}
else if (data < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
// 获取红黑树最左侧节点
Node* LeftMost()
{
return _head->_left;
}
// 获取红黑树最右侧节点
Node* RightMost()
{
return _head->_right;
}
// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
bool IsValidRBTRee()
{
Node* root = GetRoot();
if (root->_col == RED)
{
return false;
}
if (root == nullptr)
{
return true;
}
int blackc = GetBlackCount(GetRoot());
int blacknum = 0;
_IsValidRBTRee(GetRoot(), blackc, blacknum);
}
void InOrder()
{
_InOrder(GetRoot());
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_data << " ";
_InOrder(root->_right);
}
size_t GetBlackCount(Node* root)
{
size_t ret = 0;
Node* cur = root;
while (cur)
{
if (cur->_col == BLACK)
{
ret++;
}
cur = cur->_left;
}
ret++;
return ret;
}
bool _IsValidRBTRee(Node* root, size_t blackCount, size_t pathBlack)
{
if (root == nullptr)
{
pathBlack++;
if (pathBlack != blackCount)
{
cout << "各路径黑色结点数量不同" << endl;
return false;
}
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
return false;
}
if (root->_col == BLACK)
{
pathBlack++;
}
return _IsValidRBTRee(root->_left, blackCount, pathBlack)
&& _IsValidRBTRee(root->_right, blackCount, pathBlack);
}
// 右单旋
void RotateR(Node* parent)
{
Node* pprent = parent->_parent;
Node* pl = parent->_left;
Node* PRL = pl->_right;
Node* PR = parent;
//更新与上一节点的链接关系
if (parent == GetRoot())
{
_head->_parent = pl;
pl->_parent = nullptr;
}
else
{
if (pprent->_left == parent)
{
pprent->_left = pl;
}
else
{
pprent->_right = pl;
}
pl->_parent = pprent;
}
pl->_right = PR;
PR->_parent = pl;
PR->_left = PRL;
if (PRL)
PRL->_parent = PR;
}
// 左单旋
void RotateL(Node* parent)
{
Node* pprent = parent->_parent;
Node* pr = parent->_right;
Node* PLR = pr->_left;
Node* PL = parent;
//更新与上一节点的链接关系
if (parent == GetRoot())
{
_head->_parent = pr;
pr->_parent = nullptr;
}
else
{
if (pprent->_left == parent)
{
pprent->_left = pr;
}
else
{
pprent->_right = pr;
}
pr->_parent = pprent;
}
pr->_left = PL;
PL->_parent = pr;
PL->_right = PLR;
if (PLR)
PLR->_parent = PL;
}
// 为了操作树简单起见:获取根节点
Node* GetRoot()
{
if (_head->_parent == _head)
{
return nullptr;
}
else
{
return _head->_parent;
}
}
private:
Node* _head;
};