一、前言
上篇博客中,我们了解并实现了 AVL树,在 AVL树 的基础上我们再去实现比较抽象的红黑树就容易多了。请注意,这篇博客不会再重复讲旋转操作,旋转操作请参考: AVL树介绍、实现与封装
以下代码环境为 VS2022 C++。
二、红黑树的概念
红黑树是一棵自平衡二叉搜索树,他的每个结点增加一个存储位来表示结点的颜色,可以是红色或者黑色。通过对任何一条从根到叶子的路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出 2 倍,因而是接近平衡的。
红黑树的规则
-
每个结点不是红色就是黑色。
-
根结点是黑色的。
-
如果一个结点是红色的,则它的两个孩子结点必须是黑色的,也就是说任意一条路径不会有连续的红色结点。
-
对于任意一个结点,从该结点到其所有 NULL(空节点) 结点的简单路径上,均包含相同数量的黑色结点。
红黑树最长路径不超过最短路径的2倍
由规则 4 可知,从根到 NULL 结点的每条路径都有相同数量的黑色结点,所以极端场景下,最短路径就是全是黑色结点的路径,假设最短路径长度为 bh (black height)。
由规则 2 和规则 3 可知,任意一条路径不会有连续的红色结点,所以极端场景下,最长的路径就是一黑一红间隔组成,那么最长路径的长度为 2 * bh。
综合红黑树的 4 点规则而言,理论上的 全黑最短路径 和 一黑一红的最长路径 并不是在每棵红黑树都存在的。假设任意一条从根到 NULL 结点路径的长度为 h ,那么 bh <= h <= 2 * bh。
红黑树的效率
假设 N 是红黑树树中结点数量,h 最短路径的长度,那么 2 ^ h - 1 <= N < 2 ^ (2 * h) - 1,由此推出 h ≈ logN,也就是意味着红黑树增删查改最坏也就是走最长路径 2 * log N,那么时间复杂度还是 O(logN)。
红黑树的表达相对 AVL 树要抽象一些,AVL 树通过高度差直观的控制了平衡。红黑树通过 4 条规则的颜色约束,间接的实现了近似平衡,他们效率都是同一档次,但是相对而言,插入相同数量的结点,红黑树的旋转次数是更少的,因为他对平衡的控制没那么严格。
三、红黑树的实现
红黑树的结构
template<class Key, class Value>
class RBTree
{
typedef std::pair<Key, Value> Type;
enum Color
{
RED,
BLACK
};
// 1. 红黑树节点要么为黑,要么为红
// 2. 根节点为黑
// 3. 红节点孩子不能为红
// 4. 每个路径的黑节点个数相同
struct RBTreeNode
{
RBTreeNode(const Type& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
,_color(RED)
{
;
}
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Type _data;
Color _color;
};
typedef RBTreeNode Node;
typedef Node* pNode;
pNode _root = nullptr;
};
抽象图的标注
注意之后的图片会使用抽象的红黑树表示方法,这里给出标注:
红黑树的插入
红黑树插入一个值的大概过程
-
插入一个值按二叉搜索树规则进行插入,插入后我们只需要观察是否符合红黑树的 4 条规则。
-
如果是空树插入,新增结点是黑色结点。如果是非空树插入,新增结点必须是红色结点,因为非空树插入,新增黑色结点就破坏了规则 4,规则 4 是很难维护的。
-
非空树插入后,新增结点必须红色结点,如果父亲结点是黑色的,则没有违反任何规则,插入结束。
-
非空树插入后,新增结点必须红色结点,如果父亲结点是红色的,则违反规则 3 。进一步分析,c 是红色,p 为红,g 必为黑,这三个颜色都固定了,关键的变化看 u 的情况,需要根据 u 分为以下几种情况分别处理。
说明:下图中假设我们把新增结点标识为 c(cur),c的父亲标识为 p(parent),p 的父亲标识为 g(grandfather),p的兄弟标识为 u(uncle)。
情况1:变色
c 为红,p 为红,g 为黑,u 存在且为红,则将 p 和 u 变黑,g 变红。在把 g 当做新的 c,继续往上更新。
分析:因为 p 和 u 都是红色,g 是黑色,把 p 和 u 变黑,左边子树路径各增加一个黑色结点,g 再变红,相当于保持 g 所在子树的黑色结点的数量不变,同时解决了 c 和 p 连续红色结点的问题,需要继续往上更新是因为,g 是红色,如果 g 的父亲还是红色,那么就还需要继续处理;如果 g 的父亲是黑色,则处理结束了;如果 g 就是整棵树的根,再把 g 变回黑色。
情况1 只变色,不旋转。所以无论 c 是 p 的左还是右,p 是 g 的左还是右,都是上面的变色处理方式。
跟AVL树类似,我们展示只了一种具体情况,但是实际中需要这样处理的有很多种情况。
上图将以上类似的处理进行了抽象表达,d / e / f 代表每条路径拥有 bh 个黑色结点的子树, a / b 代表每条路径拥有 bh - 1 个黑色结点的根为红的子树,bh >= 1。不论情况多少种,多么复杂,处理方式一样的,变色再继续往上处理即可,所以我们只需要看抽象图即可。
情况2:单旋 + 变色
c 为红,p 为红,g 为黑,u 不存在或者 u 存在且为黑。u 不存在,则 c 一定是新增结点,u 存在且为黑,则 c 一定不是新增,c 之前是黑色的,是在 c 的子树中插入,符合情况1,变色将 c 从黑色变成红色,更新上来的。
分析:p 必须变黑,才能解决,连续红色结点的问题,u 不存在或者是黑色的,这里单纯的变色无法解决问题,需要旋转 + 变色。
如果 p 是 g 的左,c 是 p 的左,那么以 g 为旋转点进行右单旋,再把 p 变黑,g 变红即可。p 变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为p的父亲是黑色还是红色或者空都不违反规则。
如果 p 是 g 的右,c 是 p 的右,那么以 g 为旋转点进行左单旋,再把 p 变黑,g 变红即可。p 变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为 p 的父亲是黑色还是红色或者空都不违反规则。
情况2:双旋 + 变色
c 为红,p 为红,g 为黑,u 不存在或者 u 存在且为黑。u 不存在,则 c 一定是新增结点,u 存在且为黑,则 c 一定不是新增,c 之前是黑色的,是在 c 的子树中插入,符合情况1,变色将 c 从黑色变成红色,更新上来的。
分析:p 必须变黑,才能解决,连续红色结点的问题,u 不存在或者是黑色的,这里单纯的变色无法解决问题,需要旋转 + 变色。
如果 p 是 g 的左,c 是 p 的右,那么先以 p 为旋转点进行左单旋,再以 g 为旋转点进行右单旋,再把 c 变黑,g 变红即可。c 变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为 c 的父亲是黑色还是红色或者空都不违反规则。
如果 p 是 g 的右,c 是 p 的左,那么先以 p 为旋转点进行右单旋,再以 g 为旋转点进行左单旋,再把 c 变黑,g 变红即可。c 变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为 c 的父亲是黑色还是红色或者空都不违反规则。
红黑树的插入代码实现
bool insert(const Type& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_color = BLACK; // 保证根节点为黑色
return true;
}
pNode parent = _root;
pNode cur = _root;
while (cur != nullptr) // 按二叉搜索树规则进行插入
{
parent = cur;
if (cur->_data.first < data.first)
{
cur = cur->_right;
}
else if (cur->_data.first > data.first)
{
cur = cur->_left;
}
else
{
return false; // 无重复值处理
}
}
cur = new Node(data); // 新增结点必须红色结点
if (parent->_data.first < data.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
pNode grandparent = parent->_parent;
while (grandparent != nullptr)
{
if (parent->_color == BLACK) // 父亲节点为黑色直接退出
{
break;
}
if (grandparent->_left == parent) // p 在 g 左边
{
pNode uncle = grandparent->_right;
if (uncle && uncle->_color == RED) // 只变色,继续向上调整
{
grandparent->_color = RED;
uncle->_color = parent->_color = BLACK;
}
else
{
if (parent->_left == cur) // c 在 p 左边,右旋变色
{
rotateR(grandparent);
grandparent->_color = RED;
parent->_color = BLACK;
}
else // c 在 p 右边,左右旋变色
{
rotateL(parent);
rotateR(grandparent);
grandparent->_color = RED;
cur->_color = BLACK;
}
break; // 旋转完后退出
}
}
else // p 在 g 右边
{
pNode uncle = grandparent->_left;
if (uncle && uncle->_color == RED)
{
grandparent->_color = RED;
uncle->_color = parent->_color = BLACK;
}
else
{
if (parent->_right == cur) // c 在 p 右边,左旋变色
{
rotateL(grandparent);
grandparent->_color = RED;
parent->_color = BLACK;
}
else // c 在 p 左边,右左旋变色
{
rotateR(parent);
rotateL(grandparent);
grandparent->_color = RED;
cur->_color = BLACK;
}
break;
}
}
cur = grandparent; // 向上继续调整
parent = cur->_parent;
if (parent != nullptr)
{
grandparent = parent->_parent;
}
else
{
grandparent = nullptr;
}
}
_root->_color = BLACK; // 保证根节点为黑色
return true;
}
红黑树的查找
按二叉搜索树逻辑实现即可,搜索效率为 O(logN)
pNode find(const Key& key)
{
pNode cur = _root;
while (cur != nullptr)
{
if (cur->_data.first < key)
{
cur = cur->_right;
}
else if (cur->_data.first > key)
{
cur = cur->_left;
}
else
{
break;
}
}
return cur;
}
红黑树的验证
这里获取最长路径和最短路径,检查最长路径不超过最短路径的 2 倍是不可行的,因为就算满足这个条件,红黑树也可能颜色不满足规则,当前暂时没出问题,后续继续插入还是会出问题的。所以我们还是去检查 4 点规则,满足这 4 点规则,一定能保证最长路径不超过最短路径的 2 倍。
-
规则1枚举颜色类型,天然实现保证了颜色不是黑色就是红色。
-
规则2直接检查根即可。
-
规则3前序遍历检查,遇到红色结点查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲的颜色就方便多了。
-
规则4前序遍历,遍历过程中用形参记录跟到当前结点的 blackNum(黑色结点数量),前序遍历遇到黑色结点就 ++blackNum,走到空就计算出了一条路径的黑色结点数量。再任意一条路径黑色结点数量作为参考值,依次比较即可。
size_t countBlack()
{
pNode cur = _root;
size_t count = 0;
while (cur != nullptr)
{
if (cur->_color == BLACK)
{
++count;
}
cur = cur->_left;
}
return count;
}
static bool _isRBTree(pNode root, size_t countBlack, size_t pathBlack)
{
if (root == nullptr)
{
if (countBlack != pathBlack)
{
std::cout << "存在黑色节点的数量不相等的路径" << std::endl;
return false;
}
return true;
}
if (root->_color == RED && root->_parent->_color == root->_color)
{
std::cout << "存在连续的红色节点" << std::endl;
return false;
}
if (root->_color == BLACK)
{
++countBlack;
}
return _isRBTree(root->_left, countBlack, pathBlack) &&
_isRBTree(root->_right, countBlack, pathBlack);
}
bool isRBTree()
{
return _isRBTree(_root, 0, countBlack());
}
红黑树的删除
红黑树的删除在旋转时还需要考虑变色,相对于 AVL树 更难以理解,这里我们依然采取枚举所有情况的方法。
红黑树删除与二叉搜索树的删除一样,分为四种情况:
-
要删除节点 H 左右孩子均为空。
-
要删除的节点 H 左孩子为空,右孩子节点不为空。
-
要删除的节点 H 右孩子为空,左孩子节点不为空。
-
要删除的节点 H 左右孩子节点均不为空。
注意到,我们的调整只针对被删除节点是黑色的,红色节点删除后一定不会违反所有规则,不用旋转变色与向上调整。
这里我们采取先删除后向上调整。
删除枚举
为方便讲解,这里调整一下顺序:
要删除的节点 H 左孩子为空,右孩子节点不为空
注意 bh == 1:
要删除的节点 H 右孩子为空,左孩子节点不为空
注意 bh == 1:
要删除的节点 H 左右孩子节点均不为空
我们使用替换法解决,在被删除节点的右孩子(或左孩子)开始,一直向下找到最小(或最大)的节点,然后交换两者数据。这里我采用从右孩子开始,向下找最小节点。
则对于第 4 种情况可以借用替换法转化成第 1 种情况 或 第 2 种情况:
要删除节点 H 左右孩子均为空
当被删除节点的 parent 颜色为红色时:
当被删除节点 parent 颜色为黑色时:
单独讨论
当 parent 为黑色,被删节点的兄弟节点是红色时比较特殊,不能单纯变色和旋转处理:
可以看到,若右下角的红色节点有孩子,就一定是红色,违反了规则3。
这里有两种处理方式:
局部套用
可以看到,左旋 + 变色可以将这个问题转为 parent 为红色来处理,我们上面已经讨论 parent 为红色时一定可以处理完成并不用向上调整,则这种方法也不用向上调整,对删除节点在 parent 右边同样适用,这里省略。
替换法
我们可以利用节点被删除这一特点,使用替换法:
可以显然观察到,要么删除的是值为 " 33 " 的黑色节点,要么就是它的左孩子,所以并不用向上调整。
但是注意,图片中删除 parent 左节点使用的是采用从右孩子开始,向下找最小节点的替换方法,不适用于删除 parent 右节点,需要单独实现采用从左孩子开始,向下找最大节点的函数,调用不方便。
删除代码实现
// N 表示空,H 表示有节点
// NN 表示 左右为空
// NH 表示 左为空 右有节点
// HN 表示 左有节点 右为空
void erase_NH_or_HN(pNode parent, pNode aim, pNode aimChild)
{
if (parent == nullptr) // 为根节点时
{
_root = aimChild;
_root->_parent = nullptr;
}
else if (parent->_left == aim) // 在左边
{
parent->_left = aimChild;
parent->_left->_parent = parent;
parent->_left->_color = BLACK;
}
else // 在右边
{
parent->_right = aimChild;
parent->_right->_parent = parent;
parent->_right->_color = BLACK;
}
}
void replace(pNode& parent, pNode& aim, pNode& checkParent, pNode& checkChild)
{
pNode prev = aim;
pNode cur = aim->_right; // 从右孩子找最小值
while (cur != nullptr)
{
prev = cur;
cur = cur->_left;
}
std::swap(prev->_data, aim->_data); // 替换值
parent = prev->_parent; // parent 更新
std::swap(prev, aim); // 指针交换
if (aim->_right != nullptr) // 不为空走第 2 种情况,反之第 1 种情况
{
erase_NH_or_HN(parent, aim, aim->_right);
}
else
{
eraseNN(parent, aim, checkParent, checkChild);
}
}
void eraseNN(pNode& parent, pNode& aim, pNode& checkParent, pNode& checkChild)
{
if (parent == nullptr)
{
_root = nullptr;
}
else if (aim->_color == RED) // 为红色直接置空即可
{
if (parent->_left == aim)
{
parent->_left = nullptr;
}
else
{
parent->_right = nullptr;
}
}
else if (parent->_color == RED) // parent 为红色的枚举
{
if (parent->_left == aim) // 在左边
{
parent->_left = nullptr;
pNode uncle = parent->_right; // 此时 uncle 一定为黑色
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
parent->_color = BLACK;
uncle->_color = RED;
}
else if (uncle->_left == nullptr)
{
rotateL(parent);
}
else if (uncle->_right == nullptr)
{
rotateR(uncle);
rotateL(parent);
parent->_color = BLACK;
}
else
{
rotateL(parent);
uncle->_color = RED;
parent->_color = uncle->_right->_color = BLACK;
}
}
else // 在右边
{
parent->_right = nullptr;
pNode uncle = parent->_left; // 此时 uncle 一定为黑色
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
parent->_color = BLACK;
uncle->_color = RED;
}
else if (uncle->_left == nullptr)
{
rotateL(uncle);
rotateR(parent);
parent->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(parent);
}
else
{
rotateR(parent);
uncle->_color = RED;
parent->_color = uncle->_left->_color = BLACK;
}
}
}
else // parent 为黑色的枚举
{
if (parent->_left == aim) // 在左边
{
pNode uncle = parent->_right;
parent->_left = nullptr;
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
uncle->_color = RED;
// 需要向上调整
checkChild = parent;
checkParent = checkChild->_parent;
}
else if (uncle->_left == nullptr)
{
rotateL(parent);
uncle->_right->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(uncle);
rotateL(parent);
uncle->_parent->_color = BLACK;
}
else if (uncle->_color == BLACK)
{
rotateL(parent);
uncle->_right->_color = BLACK;
}
else // 局部向上调整
{
parent->_left = aim;
rotateL(parent);
std::swap(parent->_color, uncle->_color);
eraseNN(parent, aim, checkParent, checkChild);
}
}
else // 在右边
{
pNode uncle = parent->_left;
parent->_right = nullptr;
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
uncle->_color = RED;
// 需要向上调整
checkChild = parent;
checkParent = checkChild->_parent;
}
else if (uncle->_left == nullptr)
{
rotateL(uncle);
rotateR(parent);
uncle->_parent->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(parent);
uncle->_left->_color = BLACK;
}
else if (uncle->_color == BLACK)
{
rotateR(parent);
uncle->_left->_color = BLACK;
}
else // 局部向上调整
{
parent->_right = aim;
rotateR(parent);
std::swap(parent->_color, uncle->_color);
eraseNN(parent, aim, checkParent, checkChild);
}
}
}
}
向上调整枚举
向上调整枚举与被删节点左右孩子为空类似。
注意到所有的删除节点情况中,只有被删除节点左右孩子为空,它的 parent 节点与兄弟节点都为黑色,且兄弟节点没有孩子才会向上调整。则可以确定的是,第一次向上调整的 checkChild(作用为判断调整时的孩子是 checkParent 的左边还是右边)一定为黑色:
另外,在下图展示调整的红黑树,它整体单个路径定为 bh:
当 checkParent 为红色时
注意这里的 bh >= 2:
我们旋转变色的主要目的是将这个局部的红黑树所有单个路劲恢复到 bh,这里只枚举 checkChild 为左的情况:
当 checkParent 为黑色时
注意这里的 bh >= 3:
我们旋转变色的主要目的是将这个局部的红黑树所有单个路劲恢复到 bh,这里只枚举 checkChild 为左的情况:
注意到这里只有一种向上调整的可能,即当 parent 为黑色、兄弟节点与它的左右节点都为黑色时,才会出现再次向上调整。
checkParent 向上找 _parent,checkParent 原来的节点变为 checkChild,checkChild 依然是黑色,则可以肯定的是,继续向上调整的所有情况中,checkChild 一定是黑色的,而向上调整最多调整到 checkParent 为红黑树的根节点就停止了。
向上调整实现
void parentIsRedAdjust_constSolve(pNode parent, pNode child)
{
if (parent->_left == child) // 在左边
{
pNode brother = parent->_right;
if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
parent->_color = BLACK;
brother->_color = RED;
}
else if (brother->_left->_color == BLACK)
{
rotateL(parent);
}
else if (brother->_right->_color == BLACK)
{
std::swap(brother->_left->_color, brother->_color);
rotateR(brother);
rotateL(parent);
}
else
{
rotateR(brother);
rotateL(parent);
parent->_color = BLACK;
}
}
else // 在右边
{
pNode brother = parent->_left;
if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
parent->_color = BLACK;
brother->_color = RED;
}
else if (brother->_left->_color == BLACK)
{
std::swap(brother->_right->_color, brother->_color);
rotateL(brother);
rotateR(parent);
}
else if (brother->_right->_color == BLACK)
{
rotateR(parent);
}
else
{
rotateL(brother);
rotateR(parent);
parent->_color = BLACK;
}
}
}
bool parentIsBlackAdjust_solve(pNode parent, pNode child)
{
if (parent->_left == child) // 在左边
{
pNode brother = parent->_right;
if (brother->_color == RED)
{
std::swap(brother->_color, parent->_color);
rotateL(parent);
parentIsRedAdjust_constSolve(parent, child); // 局部套用
}
else if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
brother->_color = RED;
return true; // 表示需要再次向上调整
}
else if (brother->_left->_color == BLACK)
{
brother->_right->_color = BLACK;
rotateL(parent);
}
else if (brother->_right->_color == BLACK)
{
brother->_left->_color = BLACK;
rotateR(brother);
rotateL(parent);
}
else
{
brother->_left->_color = BLACK;
rotateR(brother);
rotateL(parent);
}
}
else // 在右边
{
pNode brother = parent->_left;
if (brother->_color == RED)
{
std::swap(brother->_color, parent->_color);
rotateR(parent);
parentIsRedAdjust_constSolve(parent, child); // 局部套用
}
else if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
brother->_color = RED;
return true; // 表示需要再次向上调整
}
else if (brother->_left->_color == BLACK)
{
brother->_right->_color = BLACK;
rotateL(brother);
rotateR(parent);
}
else if (brother->_right->_color == BLACK)
{
brother->_left->_color = BLACK;
rotateR(parent);
}
else
{
brother->_right->_color = BLACK;
rotateL(brother);
rotateR(parent);
}
}
return false; // 表示不需要向上调整
}
红黑树的删除代码实现
前面封装了删除与向上调整的代码,这里调用即可:
bool erase(const Key& key)
{
pNode aim = find(key);
if (aim == nullptr)
{
return false; // 没找到则删除失败
}
pNode parent = aim->_parent;
pNode checkParent = nullptr;
pNode checkChild = nullptr;
if (aim->_left == nullptr && aim->_right == nullptr)
{
eraseNN(parent, aim, checkParent, checkChild); // 可能会向上调整
}
else if (aim->_left == nullptr)
{
erase_NH_or_HN(parent, aim, aim->_right);
}
else if (aim->_right == nullptr)
{
erase_NH_or_HN(parent, aim, aim->_left);
}
else
{
replace(parent, aim, checkParent, checkChild); // 第 1 种情况可能会向上调整
}
while (checkParent != nullptr) // 当遍历完红黑树的根节点时就会退出
{
if (checkParent->_color == RED) // checkParent 为红色,只需常数次的修改,修改后退出
{
parentIsRedAdjust_constSolve(checkParent, checkChild);
break;
}
bool need_to_up = parentIsBlackAdjust_solve(checkParent, checkChild);
checkChild = checkParent; // false 表示不需要向上调整,反之需要
checkParent = (need_to_up == false ? nullptr : checkParent->_parent);
}
delete aim; // 删除节点
return true;
}
拷贝、遍历、销毁
拷贝与二叉树的先序遍历原理相同,遍历与二叉树的中序遍历相同,销毁与二叉树的后序遍历相同,这里不赘述。
// 注意传引用
static void _treeCopy(pNode& des, pNode src)
{
if (src == nullptr)
{
return;
}
des = new Node(src);
des->_color = src->_color;
_treeCopy(des->_left, src->_left);
_treeCopy(des->_right, des->_right);
if (des->_left != nullptr) // 不为空
{
des->_left->_parent = des;
}
if (des->_right != nullptr)
{
des->_right->_parent = des;
}
}
static void _treeDestory(pNode root)
{
if (root == nullptr)
{
return;
}
_treeDestory(root->_left);
_treeDestory(root->_right);
delete root;
}
static void _inOrder(pNode root)
{
if (root == nullptr)
{
return;
}
_inOrder(root->_left);
std::cout << root->_data.second << ' ';
_inOrder(root->_right);
}
四、红黑树的封装
注意到我们设计的只是 key / value 的 红黑树,还有 key 这种类型,这里将两者整合。
RBTree_base
我们先将之前介绍的基础函数都封装到一个模版类,也就是 RBTree_base 里方便后续 key / value 与 key 类型复用:
enum Color
{
RED,
BLACK
};
template<class Type, class Key, class Value, class Node, class GetKey, class GetValue, class CompareKey>
class RBTree_base
{
typedef Node* pNode;
static constexpr const GetKey _getKey = GetKey();
static constexpr const GetValue _getValue = GetValue();
static constexpr const CompareKey _comKey = CompareKey();
// 1. 红黑树节点要么为黑,要么为红
// 2. 根节点为黑
// 3. 红节点孩子不能为红
// 4. 每个路径的黑节点个数相同
pNode _root = nullptr;
size_t _size = 0;
private:
void rotateR(pNode cur)
{
pNode subL = cur->_left;
pNode subLR = subL->_right;
pNode parent = cur->_parent;
cur->_left = subLR;
if (subLR != nullptr)
{
subLR->_parent = cur;
}
subL->_right = cur;
cur->_parent = subL;
subL->_parent = parent;
if (parent == nullptr)
{
_root = subL;
}
else if (parent->_left == cur)
{
parent->_left = subL;
}
else
{
parent->_right = subL;
}
}
void rotateL(pNode cur)
{
pNode subR = cur->_right;
pNode subRL = subR->_left;
pNode parent = cur->_parent;
cur->_right = subRL;
if (subRL != nullptr)
{
subRL->_parent = cur;
}
subR->_left = cur;
cur->_parent = subR;
subR->_parent = parent;
if (parent == nullptr)
{
_root = subR;
}
else if (parent->_left == cur)
{
parent->_left = subR;
}
else
{
parent->_right = subR;
}
}
private:
static void _treeCopy(pNode& des, pNode src)
{
if (src == nullptr)
{
return;
}
des = new Node(src);
des->_color = src->_color;
_treeCopy(des->_left, src->_left);
_treeCopy(des->_right, des->_right);
if (des->_left != nullptr)
{
des->_left->_parent = des;
}
if (des->_right != nullptr)
{
des->_right->_parent = des;
}
}
static void _treeDestory(pNode root)
{
if (root == nullptr)
{
return;
}
_treeDestory(root->_left);
_treeDestory(root->_right);
delete root;
}
static void _inOrder(pNode root)
{
if (root == nullptr)
{
return;
}
_inOrder(root->_left);
std::cout << _getValue(root->_data) << ' ';
_inOrder(root->_right);
}
size_t countBlack() const
{
pNode cur = _root;
size_t count = 0;
while (cur != nullptr)
{
if (cur->_color == BLACK)
{
++count;
}
cur = cur->_left;
}
return count;
}
static bool _isRBTree(pNode root, size_t countBlack, size_t pathBlack)
{
if (root == nullptr)
{
if (countBlack != pathBlack)
{
std::cout << "存在黑色节点的数量不相等的路径" << std::endl;
return false;
}
return true;
}
if (root->_color == RED && root->_parent->_color == root->_color)
{
std::cout << "存在连续的红色节点" << std::endl;
return false;
}
if (root->_color == BLACK)
{
++countBlack;
}
return _isRBTree(root->_left, countBlack, pathBlack) &&
_isRBTree(root->_right, countBlack, pathBlack);
}
static size_t _high(pNode root)
{
if (root == nullptr)
{
return 0;
}
size_t left = _high(root->_left);
size_t right = _high(root->_right);
return (right > left ? right : left) + 1;
}
private:
// N 表示空,H 表示有节点
// NN 表示 左右为空
// NH 表示 左为空 右有节点
// HN 表示 左有节点 右为空
void erase_NH_or_HN(pNode parent, pNode aim, pNode aimChild)
{
if (parent == nullptr) // 为根节点时
{
_root = aimChild;
_root->_parent = nullptr;
}
else if (parent->_left == aim) // 在左边
{
parent->_left = aimChild;
parent->_left->_parent = parent;
parent->_left->_color = BLACK;
}
else // 在右边
{
parent->_right = aimChild;
parent->_right->_parent = parent;
parent->_right->_color = BLACK;
}
}
void replace(pNode& parent, pNode& aim, pNode& checkParent, pNode& checkChild)
{
pNode prev = aim;
pNode cur = aim->_right; // 从右孩子找最小值
while (cur != nullptr)
{
prev = cur;
cur = cur->_left;
}
std::swap(prev->_data, aim->_data); // 替换值
parent = prev->_parent; // parent 更新
std::swap(prev, aim); // 指针交换
if (aim->_right != nullptr) // 不为空走第 2 种情况,反之第 1 种情况
{
erase_NH_or_HN(parent, aim, aim->_right);
}
else
{
eraseNN(parent, aim, checkParent, checkChild);
}
}
void eraseNN(pNode& parent, pNode& aim, pNode& checkParent, pNode& checkChild)
{
if (parent == nullptr)
{
_root = nullptr;
}
else if (aim->_color == RED) // 为红色直接置空即可
{
if (parent->_left == aim)
{
parent->_left = nullptr;
}
else
{
parent->_right = nullptr;
}
}
else if (parent->_color == RED) // parent 为红色的枚举
{
if (parent->_left == aim) // 在左边
{
parent->_left = nullptr;
pNode uncle = parent->_right; // 此时 uncle 一定为黑色
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
parent->_color = BLACK;
uncle->_color = RED;
}
else if (uncle->_left == nullptr)
{
rotateL(parent);
}
else if (uncle->_right == nullptr)
{
rotateR(uncle);
rotateL(parent);
parent->_color = BLACK;
}
else
{
rotateL(parent);
uncle->_color = RED;
parent->_color = uncle->_right->_color = BLACK;
}
}
else // 在右边
{
parent->_right = nullptr;
pNode uncle = parent->_left; // 此时 uncle 一定为黑色
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
parent->_color = BLACK;
uncle->_color = RED;
}
else if (uncle->_left == nullptr)
{
rotateL(uncle);
rotateR(parent);
parent->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(parent);
}
else
{
rotateR(parent);
uncle->_color = RED;
parent->_color = uncle->_left->_color = BLACK;
}
}
}
else // parent 为黑色的枚举
{
if (parent->_left == aim) // 在左边
{
pNode uncle = parent->_right;
parent->_left = nullptr;
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
uncle->_color = RED;
// 需要向上调整
checkChild = parent;
checkParent = checkChild->_parent;
}
else if (uncle->_left == nullptr)
{
rotateL(parent);
uncle->_right->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(uncle);
rotateL(parent);
uncle->_parent->_color = BLACK;
}
else if (uncle->_color == BLACK)
{
rotateL(parent);
uncle->_right->_color = BLACK;
}
else // 局部向上调整
{
parent->_left = aim;
rotateL(parent);
std::swap(parent->_color, uncle->_color);
eraseNN(parent, aim, checkParent, checkChild);
}
}
else // 在右边
{
pNode uncle = parent->_left;
parent->_right = nullptr;
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
uncle->_color = RED;
// 需要向上调整
checkChild = parent;
checkParent = checkChild->_parent;
}
else if (uncle->_left == nullptr)
{
rotateL(uncle);
rotateR(parent);
uncle->_parent->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(parent);
uncle->_left->_color = BLACK;
}
else if (uncle->_color == BLACK)
{
rotateR(parent);
uncle->_left->_color = BLACK;
}
else // 局部向上调整
{
parent->_right = aim;
rotateR(parent);
std::swap(parent->_color, uncle->_color);
eraseNN(parent, aim, checkParent, checkChild);
}
}
}
}
void parentIsRedAdjust_constSolve(pNode parent, pNode child)
{
if (parent->_left == child) // 在左边
{
pNode brother = parent->_right;
if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
parent->_color = BLACK;
brother->_color = RED;
}
else if (brother->_left->_color == BLACK)
{
rotateL(parent);
}
else if (brother->_right->_color == BLACK)
{
std::swap(brother->_left->_color, brother->_color);
rotateR(brother);
rotateL(parent);
}
else
{
rotateR(brother);
rotateL(parent);
parent->_color = BLACK;
}
}
else // 在右边
{
pNode brother = parent->_left;
if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
parent->_color = BLACK;
brother->_color = RED;
}
else if (brother->_left->_color == BLACK)
{
std::swap(brother->_right->_color, brother->_color);
rotateL(brother);
rotateR(parent);
}
else if (brother->_right->_color == BLACK)
{
rotateR(parent);
}
else
{
rotateL(brother);
rotateR(parent);
parent->_color = BLACK;
}
}
}
bool parentIsBlackAdjust_solve(pNode parent, pNode child)
{
if (parent->_left == child) // 在左边
{
pNode brother = parent->_right;
if (brother->_color == RED)
{
std::swap(brother->_color, parent->_color);
rotateL(parent);
parentIsRedAdjust_constSolve(parent, child); // 局部套用
}
else if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
brother->_color = RED;
return true; // 表示需要再次向上调整
}
else if (brother->_left->_color == BLACK)
{
brother->_right->_color = BLACK;
rotateL(parent);
}
else if (brother->_right->_color == BLACK)
{
brother->_left->_color = BLACK;
rotateR(brother);
rotateL(parent);
}
else
{
brother->_left->_color = BLACK;
rotateR(brother);
rotateL(parent);
}
}
else // 在右边
{
pNode brother = parent->_left;
if (brother->_color == RED)
{
std::swap(brother->_color, parent->_color);
rotateR(parent);
parentIsRedAdjust_constSolve(parent, child); // 局部套用
}
else if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
brother->_color = RED;
return true; // 表示需要再次向上调整
}
else if (brother->_left->_color == BLACK)
{
brother->_right->_color = BLACK;
rotateL(brother);
rotateR(parent);
}
else if (brother->_right->_color == BLACK)
{
brother->_left->_color = BLACK;
rotateR(parent);
}
else
{
brother->_right->_color = BLACK;
rotateL(brother);
rotateR(parent);
}
}
return false; // 表示不需要向上调整
}
private:
pNode _find(const Key& key) const
{
pNode cur = _root;
while (cur != nullptr)
{
if (_comKey(_getKey(cur->_data), key) < 0)
{
cur = cur->_right;
}
else if (_comKey(_getKey(cur->_data), key) > 0)
{
cur = cur->_left;
}
else
{
break;
}
}
return cur;
}
bool _insert(const Type& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_color = BLACK;
return true;
}
pNode parent = _root;
pNode cur = _root;
while (cur != nullptr)
{
parent = cur;
if (_comKey(_getKey(cur->_data), _getKey(data)) < 0)
{
cur = cur->_right;
}
else if (_comKey(_getKey(cur->_data), _getKey(data)) > 0)
{
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(data);
if (_comKey(_getKey(parent->_data), _getKey(data)) < 0)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
pNode grandparent = parent->_parent;
while (grandparent != nullptr)
{
if (parent->_color == BLACK)
{
break;
}
if (grandparent->_left == parent)
{
pNode uncle = grandparent->_right;
if (uncle && uncle->_color == RED)
{
grandparent->_color = RED;
uncle->_color = parent->_color = BLACK;
}
else
{
if (parent->_left == cur)
{
rotateR(grandparent);
grandparent->_color = RED;
parent->_color = BLACK;
}
else
{
rotateL(parent);
rotateR(grandparent);
grandparent->_color = RED;
cur->_color = BLACK;
}
break;
}
}
else
{
pNode uncle = grandparent->_left;
if (uncle && uncle->_color == RED)
{
grandparent->_color = RED;
uncle->_color = parent->_color = BLACK;
}
else
{
if (parent->_right == cur)
{
rotateL(grandparent);
grandparent->_color = RED;
parent->_color = BLACK;
}
else
{
rotateR(parent);
rotateL(grandparent);
grandparent->_color = RED;
cur->_color = BLACK;
}
break;
}
}
cur = grandparent;
parent = cur->_parent;
if (parent != nullptr)
{
grandparent = parent->_parent;
}
else
{
grandparent = nullptr;
}
}
_root->_color = BLACK;
return true;
}
bool _erase(const Key& key)
{
pNode aim = find(key);
if (aim == nullptr)
{
return false; // 没找到则删除失败
}
pNode parent = aim->_parent;
pNode checkParent = nullptr;
pNode checkChild = nullptr;
if (aim->_left == nullptr && aim->_right == nullptr)
{
eraseNN(parent, aim, checkParent, checkChild); // 可能会向上调整
}
else if (aim->_left == nullptr)
{
erase_NH_or_HN(parent, aim, aim->_right);
}
else if (aim->_right == nullptr)
{
erase_NH_or_HN(parent, aim, aim->_left);
}
else
{
replace(parent, aim, checkParent, checkChild); // 第 1 种情况可能会向上调整
}
while (checkParent != nullptr) // 当遍历完红黑树的根节点时就会退出
{
if (checkParent->_color == RED) // checkParent 为红色,只需常数次的修改,修改后退出
{
parentIsRedAdjust_constSolve(checkParent, checkChild);
break;
}
bool need_to_up = parentIsBlackAdjust_solve(checkParent, checkChild);
checkChild = checkParent; // false 表示不需要向上调整,反之需要
checkParent = (need_to_up == false ? nullptr : checkParent->_parent);
}
delete aim; // 删除节点
return true;
}
public:
RBTree_base() = default;
RBTree_base(const RBTree_base& tree)
{
_treeCopy(_root, tree._root);
_size = tree._size;
}
RBTree_base(RBTree_base&& tree) noexcept
{
swap(tree);
}
RBTree_base& operator=(RBTree_base tree)
{
swap(tree);
return *this;
}
RBTree_base& operator=(RBTree_base&& tree)
{
swap(tree);
return *this;
}
~RBTree_base()
{
if (_root != nullptr)
{
_treeDestory(_root);
}
_root = nullptr;
_size = 0;
}
template<class InputIterator>
RBTree_base(InputIterator begin, InputIterator end)
{
while (begin != end)
{
insert(*begin);
++begin;
}
}
RBTree_base(std::initializer_list<Type> list)
{
for (const Type& e : list)
{
insert(e);
}
}
public:
void swap(const RBTree_base& tree)
{
std::swap(_root, tree._root);
std::swap(_size, tree._size);
}
bool isRBTree() const
{
return _isRBTree(_root, 0, countBlack());
}
void inOrder() const
{
_inOrder(_root);
}
pNode find(const Key& key) const
{
return _find(key);
}
bool insert(const Type& data)
{
bool access = _insert(data);
if (access == true)
{
++_size;
}
return access;
}
bool erase(const Key& key)
{
if (_size == 0)
{
return false;
}
bool access = _erase(key);
if (access == true)
{
--_size;
}
return access;
}
size_t high() const
{
return _high(_root);
}
size_t size() const
{
return _size;
}
};
key / value 复用
这里处理 Key 和 Value 获取,将 RBTree_base 组合为成员加上接口即可:
template<class Key, class Value, class CompareKey = less<Key>>
class RBTreeTwo
{
typedef std::pair<Key, Value> Type;
typedef RBTreeNode<Type> Node;
typedef Node* pNode;
typedef Node const* const_pNode;
struct GetMapKey
{
const Key& operator()(const Type& data) const
{
return data.first;
}
};
struct GetMapValue
{
const Value& operator()(const Type& data) const
{
return data.second;
}
};
RBTree_base<Type, Key, Value, Node, GetMapKey, GetMapValue, CompareKey> _base;
public:
RBTreeTwo() = default;
template<class InputIterator>
RBTreeTwo(InputIterator begin, InputIterator end)
:_base(begin, end)
{
;
}
RBTreeTwo(std::initializer_list<Type> list)
:_base(list)
{
;
}
const_pNode find(const Key& key) const // const_pNode 防止用户修改节点内容
{
return _base.find(key);
}
bool insert(const Type& data)
{
return _base.insert(data);
}
bool erase(const Key& key)
{
return _base.erase(key);
}
bool isRBTree() const
{
return _base.isRBTree();
}
void inOrder() const
{
return _base.inOrder();
}
size_t high() const
{
return _base.high();
}
size_t size() const
{
return _base.size();
}
};
key 复用
同上,这里处理 Key 和 Value 获取,将 RBTree_base 组合为成员加上接口即可:
template<class T, class CompareKey = less<T>>
class RBTreeOne
{
typedef T Type;
typedef T Key;
typedef T Value;
typedef RBTreeNode<Type> Node;
typedef Node* pNode;
typedef Node const* const_pNode;
struct GetSetKey
{
const Key& operator()(const Type& data) const
{
return data;
}
};
struct GetSetValue
{
const Value& operator()(const Type& data) const
{
return data;
}
};
RBTree_base<Type, Key, Value, Node, GetSetKey, GetSetValue, CompareKey> _base;
public:
RBTreeOne() = default;
template<class InputIterator>
RBTreeOne(InputIterator begin, InputIterator end)
:_base(begin, end)
{
;
}
RBTreeOne(std::initializer_list<Type> list)
:_base(list)
{
;
}
const_pNode find(const Key& key) const // const_pNode 防止用户修改节点内容
{
return _base.find(key);
}
bool insert(const Type& data)
{
return _base.insert(data);
}
bool erase(const Key& key)
{
return _base.erase(key);
}
bool isRBTree() const
{
return _base.isRBTree();
}
void inOrder() const
{
return _base.inOrder();
}
size_t high() const
{
return _base.high();
}
size_t size() const
{
return _base.size();
}
};
源码展示
#pragma once
#include <iostream>
#include <utility>
namespace my
{
enum Color
{
RED,
BLACK
};
template<class Type, class Key, class Value, class Node, class GetKey, class GetValue, class CompareKey>
class RBTree_base
{
typedef Node* pNode;
static constexpr const GetKey _getKey = GetKey();
static constexpr const GetValue _getValue = GetValue();
static constexpr const CompareKey _comKey = CompareKey();
// 1. 红黑树节点要么为黑,要么为红
// 2. 根节点为黑
// 3. 红节点孩子不能为红
// 4. 每个路径的黑节点个数相同
pNode _root = nullptr;
size_t _size = 0;
private:
void rotateR(pNode cur)
{
pNode subL = cur->_left;
pNode subLR = subL->_right;
pNode parent = cur->_parent;
cur->_left = subLR;
if (subLR != nullptr)
{
subLR->_parent = cur;
}
subL->_right = cur;
cur->_parent = subL;
subL->_parent = parent;
if (parent == nullptr)
{
_root = subL;
}
else if (parent->_left == cur)
{
parent->_left = subL;
}
else
{
parent->_right = subL;
}
}
void rotateL(pNode cur)
{
pNode subR = cur->_right;
pNode subRL = subR->_left;
pNode parent = cur->_parent;
cur->_right = subRL;
if (subRL != nullptr)
{
subRL->_parent = cur;
}
subR->_left = cur;
cur->_parent = subR;
subR->_parent = parent;
if (parent == nullptr)
{
_root = subR;
}
else if (parent->_left == cur)
{
parent->_left = subR;
}
else
{
parent->_right = subR;
}
}
private:
static void _treeCopy(pNode& des, pNode src)
{
if (src == nullptr)
{
return;
}
des = new Node(src);
des->_color = src->_color;
_treeCopy(des->_left, src->_left);
_treeCopy(des->_right, des->_right);
if (des->_left != nullptr)
{
des->_left->_parent = des;
}
if (des->_right != nullptr)
{
des->_right->_parent = des;
}
}
static void _treeDestory(pNode root)
{
if (root == nullptr)
{
return;
}
_treeDestory(root->_left);
_treeDestory(root->_right);
delete root;
}
static void _inOrder(pNode root)
{
if (root == nullptr)
{
return;
}
_inOrder(root->_left);
std::cout << _getValue(root->_data) << ' ';
_inOrder(root->_right);
}
size_t countBlack() const
{
pNode cur = _root;
size_t count = 0;
while (cur != nullptr)
{
if (cur->_color == BLACK)
{
++count;
}
cur = cur->_left;
}
return count;
}
static bool _isRBTree(pNode root, size_t countBlack, size_t pathBlack)
{
if (root == nullptr)
{
if (countBlack != pathBlack)
{
std::cout << "存在黑色节点的数量不相等的路径" << std::endl;
return false;
}
return true;
}
if (root->_color == RED && root->_parent->_color == root->_color)
{
std::cout << "存在连续的红色节点" << std::endl;
return false;
}
if (root->_color == BLACK)
{
++countBlack;
}
return _isRBTree(root->_left, countBlack, pathBlack) &&
_isRBTree(root->_right, countBlack, pathBlack);
}
static size_t _high(pNode root)
{
if (root == nullptr)
{
return 0;
}
size_t left = _high(root->_left);
size_t right = _high(root->_right);
return (right > left ? right : left) + 1;
}
private:
// N 表示空,H 表示有节点
// NN 表示 左右为空
// NH 表示 左为空 右有节点
// HN 表示 左有节点 右为空
void erase_NH_or_HN(pNode parent, pNode aim, pNode aimChild)
{
if (parent == nullptr) // 为根节点时
{
_root = aimChild;
_root->_parent = nullptr;
}
else if (parent->_left == aim) // 在左边
{
parent->_left = aimChild;
parent->_left->_parent = parent;
parent->_left->_color = BLACK;
}
else // 在右边
{
parent->_right = aimChild;
parent->_right->_parent = parent;
parent->_right->_color = BLACK;
}
}
void replace(pNode& parent, pNode& aim, pNode& checkParent, pNode& checkChild)
{
pNode prev = aim;
pNode cur = aim->_right; // 从右孩子找最小值
while (cur != nullptr)
{
prev = cur;
cur = cur->_left;
}
std::swap(prev->_data, aim->_data); // 替换值
parent = prev->_parent; // parent 更新
std::swap(prev, aim); // 指针交换
if (aim->_right != nullptr) // 不为空走第 2 种情况,反之第 1 种情况
{
erase_NH_or_HN(parent, aim, aim->_right);
}
else
{
eraseNN(parent, aim, checkParent, checkChild);
}
}
void eraseNN(pNode& parent, pNode& aim, pNode& checkParent, pNode& checkChild)
{
if (parent == nullptr)
{
_root = nullptr;
}
else if (aim->_color == RED) // 为红色直接置空即可
{
if (parent->_left == aim)
{
parent->_left = nullptr;
}
else
{
parent->_right = nullptr;
}
}
else if (parent->_color == RED) // parent 为红色的枚举
{
if (parent->_left == aim) // 在左边
{
parent->_left = nullptr;
pNode uncle = parent->_right; // 此时 uncle 一定为黑色
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
parent->_color = BLACK;
uncle->_color = RED;
}
else if (uncle->_left == nullptr)
{
rotateL(parent);
}
else if (uncle->_right == nullptr)
{
rotateR(uncle);
rotateL(parent);
parent->_color = BLACK;
}
else
{
rotateL(parent);
uncle->_color = RED;
parent->_color = uncle->_right->_color = BLACK;
}
}
else // 在右边
{
parent->_right = nullptr;
pNode uncle = parent->_left; // 此时 uncle 一定为黑色
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
parent->_color = BLACK;
uncle->_color = RED;
}
else if (uncle->_left == nullptr)
{
rotateL(uncle);
rotateR(parent);
parent->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(parent);
}
else
{
rotateR(parent);
uncle->_color = RED;
parent->_color = uncle->_left->_color = BLACK;
}
}
}
else // parent 为黑色的枚举
{
if (parent->_left == aim) // 在左边
{
pNode uncle = parent->_right;
parent->_left = nullptr;
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
uncle->_color = RED;
// 需要向上调整
checkChild = parent;
checkParent = checkChild->_parent;
}
else if (uncle->_left == nullptr)
{
rotateL(parent);
uncle->_right->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(uncle);
rotateL(parent);
uncle->_parent->_color = BLACK;
}
else if (uncle->_color == BLACK)
{
rotateL(parent);
uncle->_right->_color = BLACK;
}
else // 局部向上调整
{
parent->_left = aim;
rotateL(parent);
std::swap(parent->_color, uncle->_color);
eraseNN(parent, aim, checkParent, checkChild);
}
}
else // 在右边
{
pNode uncle = parent->_left;
parent->_right = nullptr;
if (uncle->_left == nullptr && uncle->_right == nullptr)
{
uncle->_color = RED;
// 需要向上调整
checkChild = parent;
checkParent = checkChild->_parent;
}
else if (uncle->_left == nullptr)
{
rotateL(uncle);
rotateR(parent);
uncle->_parent->_color = BLACK;
}
else if (uncle->_right == nullptr)
{
rotateR(parent);
uncle->_left->_color = BLACK;
}
else if (uncle->_color == BLACK)
{
rotateR(parent);
uncle->_left->_color = BLACK;
}
else // 局部向上调整
{
parent->_right = aim;
rotateR(parent);
std::swap(parent->_color, uncle->_color);
eraseNN(parent, aim, checkParent, checkChild);
}
}
}
}
void parentIsRedAdjust_constSolve(pNode parent, pNode child)
{
if (parent->_left == child) // 在左边
{
pNode brother = parent->_right;
if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
parent->_color = BLACK;
brother->_color = RED;
}
else if (brother->_left->_color == BLACK)
{
rotateL(parent);
}
else if (brother->_right->_color == BLACK)
{
std::swap(brother->_left->_color, brother->_color);
rotateR(brother);
rotateL(parent);
}
else
{
rotateR(brother);
rotateL(parent);
parent->_color = BLACK;
}
}
else // 在右边
{
pNode brother = parent->_left;
if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
parent->_color = BLACK;
brother->_color = RED;
}
else if (brother->_left->_color == BLACK)
{
std::swap(brother->_right->_color, brother->_color);
rotateL(brother);
rotateR(parent);
}
else if (brother->_right->_color == BLACK)
{
rotateR(parent);
}
else
{
rotateL(brother);
rotateR(parent);
parent->_color = BLACK;
}
}
}
bool parentIsBlackAdjust_solve(pNode parent, pNode child)
{
if (parent->_left == child) // 在左边
{
pNode brother = parent->_right;
if (brother->_color == RED)
{
std::swap(brother->_color, parent->_color);
rotateL(parent);
parentIsRedAdjust_constSolve(parent, child); // 局部套用
}
else if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
brother->_color = RED;
return true; // 表示需要再次向上调整
}
else if (brother->_left->_color == BLACK)
{
brother->_right->_color = BLACK;
rotateL(parent);
}
else if (brother->_right->_color == BLACK)
{
brother->_left->_color = BLACK;
rotateR(brother);
rotateL(parent);
}
else
{
brother->_left->_color = BLACK;
rotateR(brother);
rotateL(parent);
}
}
else // 在右边
{
pNode brother = parent->_left;
if (brother->_color == RED)
{
std::swap(brother->_color, parent->_color);
rotateR(parent);
parentIsRedAdjust_constSolve(parent, child); // 局部套用
}
else if (brother->_left->_color == BLACK && brother->_right->_color == BLACK)
{
brother->_color = RED;
return true; // 表示需要再次向上调整
}
else if (brother->_left->_color == BLACK)
{
brother->_right->_color = BLACK;
rotateL(brother);
rotateR(parent);
}
else if (brother->_right->_color == BLACK)
{
brother->_left->_color = BLACK;
rotateR(parent);
}
else
{
brother->_right->_color = BLACK;
rotateL(brother);
rotateR(parent);
}
}
return false; // 表示不需要向上调整
}
private:
pNode _find(const Key& key) const
{
pNode cur = _root;
while (cur != nullptr)
{
if (_comKey(_getKey(cur->_data), key) < 0)
{
cur = cur->_right;
}
else if (_comKey(_getKey(cur->_data), key) > 0)
{
cur = cur->_left;
}
else
{
break;
}
}
return cur;
}
bool _insert(const Type& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_color = BLACK;
return true;
}
pNode parent = _root;
pNode cur = _root;
while (cur != nullptr)
{
parent = cur;
if (_comKey(_getKey(cur->_data), _getKey(data)) < 0)
{
cur = cur->_right;
}
else if (_comKey(_getKey(cur->_data), _getKey(data)) > 0)
{
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(data);
if (_comKey(_getKey(parent->_data), _getKey(data)) < 0)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
pNode grandparent = parent->_parent;
while (grandparent != nullptr)
{
if (parent->_color == BLACK)
{
break;
}
if (grandparent->_left == parent)
{
pNode uncle = grandparent->_right;
if (uncle && uncle->_color == RED)
{
grandparent->_color = RED;
uncle->_color = parent->_color = BLACK;
}
else
{
if (parent->_left == cur)
{
rotateR(grandparent);
grandparent->_color = RED;
parent->_color = BLACK;
}
else
{
rotateL(parent);
rotateR(grandparent);
grandparent->_color = RED;
cur->_color = BLACK;
}
break;
}
}
else
{
pNode uncle = grandparent->_left;
if (uncle && uncle->_color == RED)
{
grandparent->_color = RED;
uncle->_color = parent->_color = BLACK;
}
else
{
if (parent->_right == cur)
{
rotateL(grandparent);
grandparent->_color = RED;
parent->_color = BLACK;
}
else
{
rotateR(parent);
rotateL(grandparent);
grandparent->_color = RED;
cur->_color = BLACK;
}
break;
}
}
cur = grandparent;
parent = cur->_parent;
if (parent != nullptr)
{
grandparent = parent->_parent;
}
else
{
grandparent = nullptr;
}
}
_root->_color = BLACK;
return true;
}
bool _erase(const Key& key)
{
pNode aim = find(key);
if (aim == nullptr)
{
return false; // 没找到则删除失败
}
pNode parent = aim->_parent;
pNode checkParent = nullptr;
pNode checkChild = nullptr;
if (aim->_left == nullptr && aim->_right == nullptr)
{
eraseNN(parent, aim, checkParent, checkChild); // 可能会向上调整
}
else if (aim->_left == nullptr)
{
erase_NH_or_HN(parent, aim, aim->_right);
}
else if (aim->_right == nullptr)
{
erase_NH_or_HN(parent, aim, aim->_left);
}
else
{
replace(parent, aim, checkParent, checkChild); // 第 1 种情况可能会向上调整
}
while (checkParent != nullptr) // 当遍历完红黑树的根节点时就会退出
{
if (checkParent->_color == RED) // checkParent 为红色,只需常数次的修改,修改后退出
{
parentIsRedAdjust_constSolve(checkParent, checkChild);
break;
}
bool need_to_up = parentIsBlackAdjust_solve(checkParent, checkChild);
checkChild = checkParent; // false 表示不需要向上调整,反之需要
checkParent = (need_to_up == false ? nullptr : checkParent->_parent);
}
delete aim; // 删除节点
return true;
}
public:
RBTree_base() = default;
RBTree_base(const RBTree_base& tree)
{
_treeCopy(_root, tree._root);
_size = tree._size;
}
RBTree_base(RBTree_base&& tree) noexcept
{
swap(tree);
}
RBTree_base& operator=(RBTree_base tree)
{
swap(tree);
return *this;
}
RBTree_base& operator=(RBTree_base&& tree)
{
swap(tree);
return *this;
}
~RBTree_base()
{
if (_root != nullptr)
{
_treeDestory(_root);
}
_root = nullptr;
_size = 0;
}
template<class InputIterator>
RBTree_base(InputIterator begin, InputIterator end)
{
while (begin != end)
{
insert(*begin);
++begin;
}
}
RBTree_base(std::initializer_list<Type> list)
{
for (const Type& e : list)
{
insert(e);
}
}
public:
void swap(const RBTree_base& tree)
{
std::swap(_root, tree._root);
std::swap(_size, tree._size);
}
bool isRBTree() const
{
return _isRBTree(_root, 0, countBlack());
}
void inOrder() const
{
_inOrder(_root);
}
pNode find(const Key& key) const
{
return _find(key);
}
bool insert(const Type& data)
{
bool access = _insert(data);
if (access == true)
{
++_size;
}
return access;
}
bool erase(const Key& key)
{
if (_size == 0)
{
return false;
}
bool access = _erase(key);
if (access == true)
{
--_size;
}
return access;
}
size_t high() const
{
return _high(_root);
}
size_t size() const
{
return _size;
}
};
template<class Key>
struct less
{
int operator()(const Key& one, const Key& two) const
{
if (one < two)
{
return -1;
}
else if (one > two)
{
return 1;
}
return 0;
}
};
template<class Key>
struct greater
{
int operator()(const Key& one, const Key& two) const
{
if (one < two)
{
return 1;
}
else if (one > two)
{
return -1;
}
return 0;
}
};
template<class Type>
struct RBTreeNode
{
RBTreeNode(const Type& data = Type())
:_data(data)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _color(RED)
{
;
}
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Type _data;
Color _color;
};
template<class T, class CompareKey = less<T>>
class RBTreeOne
{
typedef T Type;
typedef T Key;
typedef T Value;
typedef RBTreeNode<Type> Node;
typedef Node* pNode;
typedef Node const* const_pNode;
struct GetSetKey
{
const Key& operator()(const Type& data) const
{
return data;
}
};
struct GetSetValue
{
const Value& operator()(const Type& data) const
{
return data;
}
};
RBTree_base<Type, Key, Value, Node, GetSetKey, GetSetValue, CompareKey> _base;
public:
RBTreeOne() = default;
template<class InputIterator>
RBTreeOne(InputIterator begin, InputIterator end)
:_base(begin, end)
{
;
}
RBTreeOne(std::initializer_list<Type> list)
:_base(list)
{
;
}
const_pNode find(const Key& key) const // const_pNode 防止用户修改节点内容
{
return _base.find(key);
}
bool insert(const Type& data)
{
return _base.insert(data);
}
bool erase(const Key& key)
{
return _base.erase(key);
}
bool isRBTree() const
{
return _base.isRBTree();
}
void inOrder() const
{
return _base.inOrder();
}
size_t high() const
{
return _base.high();
}
size_t size() const
{
return _base.size();
}
};
template<class Key, class Value, class CompareKey = less<Key>>
class RBTreeTwo
{
typedef std::pair<Key, Value> Type;
typedef RBTreeNode<Type> Node;
typedef Node* pNode;
typedef Node const* const_pNode;
struct GetMapKey
{
const Key& operator()(const Type& data) const
{
return data.first;
}
};
struct GetMapValue
{
const Value& operator()(const Type& data) const
{
return data.second;
}
};
RBTree_base<Type, Key, Value, Node, GetMapKey, GetMapValue, CompareKey> _base;
public:
RBTreeTwo() = default;
template<class InputIterator>
RBTreeTwo(InputIterator begin, InputIterator end)
:_base(begin, end)
{
;
}
RBTreeTwo(std::initializer_list<Type> list)
:_base(list)
{
;
}
const_pNode find(const Key& key) const // const_pNode 防止用户修改节点内容
{
return _base.find(key);
}
bool insert(const Type& data)
{
return _base.insert(data);
}
bool erase(const Key& key)
{
return _base.erase(key);
}
bool isRBTree() const
{
return _base.isRBTree();
}
void inOrder() const
{
return _base.inOrder();
}
size_t high() const
{
return _base.high();
}
size_t size() const
{
return _base.size();
}
};
}
整体测试(VS 2022 release 环境)
这里测试红黑树的插入删除是否正常,记录插入节点个数,与删除节点个数比较,防止一次删除多个节点导致内存泄漏。
注意我们实现的是无重复 key 的红黑树,随机数重复的话插入一定会失败:
当然,这里删除慢是因为加入了平衡检查。
源码:
#include <iostream>
#include <vector>
#include "RBTree.hpp"
using namespace std;
void test1()
{
srand((unsigned int)time(NULL));
const int N = 1000000; // 测试一百万个数随机数
vector<int> v;
v.reserve(N);
for (int i = 0; i < N; ++i)
{
int random = rand() % 10000 * 10000 + rand() % 10000;
v.push_back(random);
}
int getInsert = 0;
int getErase = 0;
my::RBTreeTwo<int, int> t;
//my::RBTreeOne<int> t;
int begin1 = clock();
for (auto& e : v)
{
getInsert += t.insert({ e, e });
//getInsert += t.insert(e);
}
int end1 = clock();
cout << "insert time:" << end1 - begin1 << endl;
bool ans = t.isRBTree();
cout << "是否平衡:" << ans << endl;
int begin2 = clock();
int check = 100; // 每删了十分之一的节点就进行检查,是否是正确的红黑树
for (auto& e : v)
{
getErase += t.erase(e);
if (getErase * check > N)
{
cout << "是否平衡:" << t.isRBTree() << endl;
check -= 10;
}
}
int end2 = clock();
cout << "erase time:" << end2 - begin2 << endl;
cout << "是否平衡:" << t.isRBTree() << endl;
cout << "删除次数:" << getErase << endl;
cout << "插入次数:" << getInsert << endl;
}
int main()
{
test1();
return 0;
}