目录
红黑树的概念
红黑树的性质
红黑树结点的定义
enum Color
{
RED,
BLACK
};
template<class k,class v>
struct RBTreeNode
{
RBTreeNode<k, v>* _left;//指向左孩子
RBTreeNode<k, v>* _right;//指向右孩子
RBTreeNode<k, v>* _parent;//指向父节点
Color _col;//结点颜色
pair<k, v> _kv;//存储有效数据
//节点类的构造函数
RBTreeNode(const pair<k, v>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED)
, _kv(kv)
{}
};
红黑树的插入
template <class k, class v>
class RBTree
{
typedef RBTreeNode<k, v> Node;
public:
//首先按照搜索二叉树的规则插入数据
bool Insert(const pair<k, v>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
//红黑树根结点为黑色
_root->_col = BLACK;
return true;
}
//parent记录父节点的位置,cur寻找插入位置
Node* parent = nullptr;
Node* cur = _root;
while (cur != nullptr)
{
//根据键值key比较,确定迭代左子树或是右子树
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);
if ((parent->_kv).first > kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//平衡化操作
//...
return true;
}
private:
Node* _root = nullptr;
};
平衡化操作
情形一:uncle结点存在且为红
具象图:
抽象图:
情形二:uncle结点不存在或者存在且为黑
uncle结点不存在
uncle结点存在且为黑
抽象图:
左旋代码实现
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subR;
}
else
{
ppnode->_right = subR;
}
subR->_parent = ppnode;
}
}
右旋代码实现
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* ppnode = parent->_parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subL;
}
else
{
ppnode->_right = subL;
}
subL->_parent = ppnode;
}
}
Insert()函数代码实现
//首先按照搜索二叉树的规则插入数据
bool Insert(const pair<k, v>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
//红黑树根结点为黑色
_root->_col = BLACK;
return true;
}
//parent记录父节点的位置,cur寻找插入位置
Node* parent = nullptr;
Node* cur = _root;
while (cur != nullptr)
{
//根据键值key比较,确定迭代左子树或是右子树
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);
if ((parent->_kv).first > kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//平衡化操作
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// 情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续往上处理
cur = grandfather;
parent = cur->_parent;
}
else
{
// 情况二:叔叔不存在或者存在且为黑
// 旋转+变色
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;
}
}
//parent==grandfather->_right
else
{
Node* uncle = grandfather->_left;
// 情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续往上处理
cur = grandfather;
parent = cur->_parent;
}
else
{
// 情况二:叔叔不存在或者存在且为黑
// 旋转+变色
// g
// u p
// c
if (cur == parent->_right)
{
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;
}
红黑树的验证
//红黑树的检测
//中序遍历检测是否满足搜索二叉树的性质
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << endl;
_InOrder(root->_right);
}
void InOrder()
{
_InOrder(_root);
}
//blackNum记录每条路径黑色结点的数量,refBlackNum为最左路径的黑色结点数量作为基准值
bool Check(Node* cur, int blackNum, int refBlackNum)
{
if (cur == nullptr)
{
if (refBlackNum != blackNum)
{
cout << "黑色节点的数量不相等" << endl;
return false;
}
return true;
}
//检测红黑树性质二
if (cur->_col == RED && cur->_parent->_col == RED)
{
cout << cur->_kv.first << "存在连续的红色节点" << endl;
return false;
}
if (cur->_col == BLACK)
++blackNum;
return Check(cur->_left, blackNum, refBlackNum)
&& Check(cur->_right, blackNum, refBlackNum);
}
bool IsRBTree()
{
//检查根结点是否为黑色
if (_root && _root->_col == RED)
return false;
//检查是否满足红黑树性质二
//思路1:如果当前节点为红色,检测它的孩子是否为红色,但孩子可能为空,需要判断孩子是否为空;
//思路2:如果当前节点为红色,我们去检测它的父亲是否为红色;
//检查是否满足红黑树性质三
//首先每个结点均需要求取从根到当前结点的黑色结点的数量(例如:根到根的黑色结点数量为1)
//将最左路径/最右路径的黑色节点数量作为基准值,求取到下一条路径的空节点时与基准值比较;
int refBlackNum = 0;//基准值
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
refBlackNum++;
cur = cur->_left;
}
return Check(_root, 0, refBlackNum);
}