
各位大佬好,我是落羽!一个坚持不断学习进步的大学生。 如果您觉得我的文章有所帮助,欢迎多多互三分享交流,一起学习进步! 也欢迎关注我的blog主页: 落羽的落羽
红黑树是一种更加特殊的平衡二叉搜索树,它在每个节点上增加一个存储位来表示 节点的颜色(红色或黑色) ,并通过几条规则确保树在插入和删除操作后仍然保持平衡。
红黑树有以下四条规则:

依靠它的几条规则,从同一结点出发红黑树没有一条路径会比其他路径长出2倍,因而也是接近平衡的。这是因为,由于从根到空结点的每条路径都有相同数量的黑色结点,所以极限场景下,理论最短路径就是全是黑色结点的路径(设长度为bh),理论最长路径是一黑一红间隔组成,长度就是2bh了。也就是说,红黑树中任意一条从根到空结点的路径x,都有bh <= x <= 2bh,确保了红黑树最长路径不超过最短路径的2倍了。
假设N是红黑树中结点数量,h是最短路径长度,那么2h -1 <= N <= 22h -1 ,推出h约等于logN,红黑树增删查改最坏情况也就是走最长路径2*logN,时间复杂度还是O(logN)。
这些规则保证了红黑树的平衡性,使得树的高度保持在logN级别。相比于AVL树,红黑树的平衡结构可以说更加“松散”,AVL树严格要求了左右子树高度差不超过1,但红黑树只要路径长不超过2倍就行,但它们的效率还是相同的水平。

红黑树的基本结构,不需要AVL树的平衡因子,而需要一个颜色成员:
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)
, _col(RED)
{ }
};
template<class K,class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
private:
Node* _root;
};红黑树的插入新结点的过程是这样的:
接下来,我们具体分析最后一条情况,又有几种场景。下面称新增结点为c,c的父亲为p,p的父亲为g,p的兄弟为u。c是红色的,p也是红色的,那么g一定是黑色的,这三者的颜色是确定的,所以关键是看u的状态(下图中只表示出cpgu结点,省略其他子树):
场景1:
u存在且为红色。这种场景下,c保持红色不变,使p和u都变成黑色,g变为红色。这样处理后,就能使包含p或u的路径的黑色结点数量保持一致。

场景2:
u存在且为黑色 或 u不存在。u不存在,则c一定是新增结点;u存在且为黑,则c一定不是新增结点,而是新增结点插入在了c的子树中通过场景1调整后使c变成了红色。
这两种情况下处理方式是一样的,需要旋转+变色处理,但是旋转变色的方式,和AVL树一样仍需分情况讨论:




红黑树的插入代码实现:
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
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;
cur->_parent = parent;
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
//p是g的左的情况
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
//u存在且为红色
//变色
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
//u不存在或存在为黑色
else //旋转+变色
{
if (cur == parent->_left)
{
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
//p是g的右的情况
else
{
Node* uncle = grandfather->_left;
//u存在且为红色
//变色
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
//u不存在或存在为黑色
else //旋转+变色
{
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}验证我们的红黑树是否合格,也就需要检查是否满足了那四条规则
bool Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr)
{
if (refNum != blackNum)
{
cout << "存在黑色结点数量不相同的路径!" << endl;
return false;
}
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
cout << "存在连续的红色结点!" << endl;
return false;
}
if (root->_col == BLACK)
{
blackNum++;
}
return Check(root->_left, blackNum, refNum) && Check(root->_right, blackNum, refNum);
}
bool IsBalance()
{
if (_root == nullptr)
{
return true;
}
if (_root->_col == RED)
{
return false;
}
//参考值refNum记录最左路径的黑色结点数量
int refNum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
refNum++;
}
cur = cur->_left;
}
return Check(_root, 0, refNum);
}本篇完,感谢阅读~