文章目录
什么是红黑树?
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。

1. 红黑树的性质
- 每个节点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子节点必须是黑色的(没有连续的红色节点)
- 对于每个节点,从该节点到其所有后代叶子节点简单路径上,均包含相同数目的黑色节点(每条路径都包含相同数量的黑色节点)
2. 红黑树节点的定义
enum Colour
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
public:
pair<K, V> _kv;
Colour _col;
RBTreeNode<K, V>* _pLeft;
RBTreeNode<K, V>* _pRight;
RBTreeNode<K, V>* _pParent;
RBTreeNode(const pair<K, V>& kv) // 构造新增节点
:_pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _kv(kv)
, _col(RED) // 默认为红色
{
}
};
在节点的定义中,为什么要将节点的默认颜色给成红色的?
红黑树是一种自平衡的二叉搜索树,其节点上会附加一个颜色属性,可以是红色或黑色。在红黑树中将节点默认颜色设置为红色有助于满足红黑树的性质,确保树的平衡性和高效性。
具体原因如下:
- 约束节点插入位置:当新节点插入红黑树时,将其默认设为红色可以帮助维持红黑树的平衡性,因为红色节点的存在不会破坏红黑树的性质,而黑色节点的插入可能会导致需要进行额外的旋转操作来调整平衡。
- 简化旋转操作:默认将节点设置为红色可以减少旋转操作的次数,因为插入红色节点后,可以通过变换颜色和旋转来达到平衡,而插入黑色节点则可能需要更多的旋转操作。
- 保证黑色平衡:红黑树要求任意一条路径上的黑色节点数量相等,因此默认将节点设置为红色可以更容易地保证这一性质,避免破坏黑色平衡。
总的来说,将节点默认设置为红色是为了简化插入和维护红黑树的操作,同时确保树的平衡性和高效性。
3. 红黑树结构
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点,如下:

4. 红黑树的插入操作
在代码实现中,红黑树的插入操作主要包括以下步骤:
- 首先按照二叉查找树的规则将新节点插入到适当的位置,并将其颜色设为红色。
- 根据红黑树的性质,通过旋转和变色操作来维持平衡性。
- 在插入过程中,根据父节点、祖父节点和叔叔节点的颜色情况,进行不同的–旋转和变色操作,确保红黑树的性质得以保持。
// 在RB树中插入值为kv的节点
bool Insert(const pair<K, V>& kv) {
// 插入节点
if (_pRoot == nullptr) {
_pRoot = new Node(kv);
_pRoot->_col = BLACK;
return true;
}
Node* pParent = nullptr;
Node* pCur = _pRoot;
while (pCur) {
pParent = pCur;
if (kv.first < pCur->_kv.first)
pCur = pCur->_pLeft; // 往左子树查找
else if (kv.first > pCur->_kv.first)
pCur = pCur->_pRight; // 往右子树查找
else
return false; // 重复值不插入
}
// 创建新节点
pCur = new Node(kv); // 红色的
if (kv.first < pParent->_kv.first)
pParent->_pLeft = pCur;
else
pParent->_pRight = pCur;
pCur->_pParent = pParent;
// 插入节点后,更新
while (pParent && pParent->_col == RED) {
Node* pGrandfather = pParent->_pParent;
if (pGrandfather == nullptr)
break; // 处理根节点
// 找叔叔
if (pParent == pGrandfather->_pLeft) {
Node* pUncle = pGrandfather->_pRight;
// case1: 叔叔存在且为RED
if (pUncle && pUncle->_col == RED) {
// 变色
pParent->_col = pUncle->_col = BLACK;
pGrandfather->_col = RED;
// 继续往上处理
pCur = pGrandfather;
pParent = pCur->_pParent;
}
else {
// case2: 叔叔不存在或者存在且为黑 (旋转+变色)
if (pCur == pParent->

最低0.47元/天 解锁文章
1363

被折叠的 条评论
为什么被折叠?



