最近结合下面的文章研究了下红黑树理论:
https://blog.youkuaiyun.com/zzy520comzzy/article/details/92688831
同时,结合理论读懂了qmap的实现源码,补充代码的注释,做个备忘。
/*
* 红黑树的规则:
* 1. 所有节点非黑即白;
* 2. 根节点为黑色节点;
* 3. 红色节点的子节点只能为黑色节点;
* 4. 从任一节点到各叶节点的黑色节点数相同;
* 5. 每个叶子节点是黑色;
* 推论:1) 黑色节点若存在父节点,则其一定有兄弟节点,否则违背规则4;
* 2) 若节点为红色节点则必定存在父节点,因为根节点为黑色;
* 3) 红色节点的所有子节点都是黑色,即不存在红色子节点。
*/
const QMapDataBase QMapDataBase::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, { 0, 0, 0 }, 0 };
const QMapNodeBase *QMapNodeBase::nextNode() const
{
const QMapNodeBase *n = this;
// 找大于当前节点的最小节点,即右子树的最左侧节点
if (n->right) {
n = n->right;
while (n->left)
n = n->left;
// 找所属左子树的根节点,找不到则空节点
} else {
const QMapNodeBase *y = n->parent();
while (y && n == y->right) {
n = y;
y = n->parent();
}
n = y;
}
return n;
}
const QMapNodeBase *QMapNodeBase::previousNode() const
{
const QMapNodeBase *n = this;
// 找到小于当前节点的最大节点,即左子树的最右侧节点
if (n->left) {
n = n->left;
while (n->right)
n = n->right;
// 找所属右子树的根节点,不存在则返回空
} else {
const QMapNodeBase *y = n->parent();
while (y && n == y->left) {
n = y;
y = n->parent();
}
n = y;
}
return n;
}
// x为旋转的中心节点,其右侧节点y取代x的位置
void QMapDataBase::rotateLeft(QMapNodeBase *x)
{
// header根节点的容器,header.left为根节点
QMapNodeBase *&root = header.left;
// 找右子节点
QMapNodeBase *y = x->right;
// 将右子节点指派给x作右节点
x->right = y->left;
// 若节点非空重新指派父节点
if (y->left != 0)
y->left->setParent(x);
// 将y的父节点关联x的父节点
y->setParent(x->parent());
// 若x为根节点,则替换y为新的根节点
if (x == root)
root = y;
// 非根节点,则必然存在父节点,将y与父节点左或者右绑定
else if (x == x->parent()->left)
x->parent()->left = y;
else
x->parent()->right = y;
// x移至y的左侧
y->left = x;
x->setParent(y);
}
// 右旋转类似左旋转
void QMapDataBase::rotateRight(QMapNodeBase *x)
{
QMapNodeBase *&root = header.left;
QMapNodeBase *y = x->left;
x->left = y->right;
if (y->right != 0)
y->right->setParent(x);
y->setParent(x->parent());
if (x == root)
root = y;
else if (x == x->parent()->right)
x->parent()->right = y;
else
x->parent()->left = y;
y->right = x;
x->setParent(y);
}
//I. 新增节点x再平衡的处理
void QMapDataBase::rebalance(QMapNodeBase *x)
{
QMapNodeBase *&root = header.left;
// 新增节点置为红色
x->setColor(QMapNodeBase::Red);
// 父节点为红色则调整否则违反规则3,要做调整
while (x != root && x->parent()->color() == QMapNodeBase::Red) {
//1. 父节点为左侧节点
if (x->parent() == x->parent()->parent()->left) {
// 父节点为红色,必定存在祖父节点
QMapNodeBase *y = x->parent()->parent()->right;
//1.1 叔节点是红色(推导:叔节点的子节点均为黑色,即不存在红色子节点)
if (y && y->color() == QMapNodeBase::Red) {
// 叔和父节点置为黑色,祖父节点置为红色,由父节点去做平衡处理
x->parent()->setColor(QMapNodeBase::Black);
y->setColor(QMapNodeBase::Black);
x->parent()->parent()->setColor(QMapNodeBase::Red);
x = x->parent()->parent();
//1.2 叔节点为空或黑色
} else {
//1.2.1 新插入节点在右侧分支,则先左旋,转换为1.2.2的场景
if (x == x->parent()->right) {
x = x->parent();
rotateLeft(x);
}
//1.2.2 新插入节点在左侧分支,即与父节点在同侧,直接右旋转
x->parent()->setColor(QMapNodeBase::Black);
x->parent()->parent()->setColor(QMapNodeBase::Red);
rotateRight (x->parent()->parent());
}
//2. 父节点为右侧节点,处理逻辑与左侧分支相似
} else {
QMapNodeBase *y = x->parent()->parent()->left;
if (y && y->color() == QMapNodeBase::Red) {
x->parent()->setColor(QMapNodeBase::Black);
y->setColor(QMapNodeBase::Black);
x->parent()->parent()->setColor(QMapNodeBase::Red);
x = x->parent()->parent();
} else {
if (x == x->parent()->left) {
x = x->parent();
rotateRight(x);
}
x->parent()->setColor(QMapNodeBase::Black);
x->parent()->parent()->setColor(QMapNodeBase::Red);
rotateLeft(x->parent()->parent());
}
}
}
root->setColor(QMapNodeBase::Black);
}
//II. 删除节点再平衡的处理
// 靶节点--z,其位置被“代删除”位置占用,节点对象(QMapNodeBase)被移出树结构
// “代删除”节点--y,顶替靶节点的位置,节点对象仍在树结构中,其源位置留空。所有的平衡操作针对该源位置
void QMapDataBase::freeNodeAndRebalance(QMapNodeBase *z)
{
QMapNodeBase *&root = header.left;
QMapNodeBase *y = z; // y-“代删除”节点
QMapNodeBase *x; // x-补位“代删除”位置的节点
QMapNodeBase *x_parent; // x_parent-“代删除”的父节点,同时也是x补位删除位后的父节点
//1. 查找“代删除”节点和补位删除位置的节点
//1.1 左侧节点为空,替代节点为其唯一的右侧节点
//推导:1) “代删除”节点与删除节点的相同,即y == z
// 2) y的一侧节点为空,则其另一侧节点至多有一个红色节点。
if (y->left == 0) {
x = y->right;
// 若当前删除的节点为最左侧节点,则重新计算和更新最左侧节点
if (y == mostLeftNode) {
//y删除后,该右侧节点则为替代删除节点后的最左侧节点
if (x)
mostLeftNode = x; // It cannot have (left) children due the red black invariant.
//右侧节点为空,则y为叶子节点,删除后的最左侧节点为其父节点
else
mostLeftNode = y->parent();
}
//1.2 左侧节点非空
} else {
// 1.2.1 右侧节点为空,则替代节点为其左侧子节点
if (y->right == 0) {
x = y->left;
} else {
// 1.2.2 右侧节点非空,则找右子树的最左侧节点为"代删除"节点
y = y->right;
while (y->left != 0)
y = y->left;
//顶替节点为“代删除”节点的右侧节点
x = y->right;
}
}
// 2. 用“代删除”节点补位到删除节点的位置
// 2.1 顶替节点与删除节点不同
// 推导:“代删除”节点的左子节点一定为空,见“代删除”节点的查找过程
if (y != z) {
// z->left为空,则y恒等于z。逆否命题:y不等z,则z->left一定不为空
//将“代删除”节点代换到靶节点:“代删除”节点左子节点为空,所以先接管靶节点左侧子节点
z->left->setParent(y);
y->left = z->left;
// y != z->right推导:1) y一定是其父节点的左侧节点;2) y一定无左子节点
if (y != z->right) {
x_parent = y->parent();
// a. 将x补位到“代删除”节点,剥离“代删除”节点,更新父子关系
if (x)
x->setParent(y->parent());
y->parent()->left = x;
// b. 将“代删除”节点代换到靶节点:接管右侧子节点,此时靶节点变为空闲节点
y->right = z->right;
z->right->setParent(y);
// y==z->right,则相当于“待删除”节点的右侧子节点整体上移:右子节点保持不变,无x的补位过程
} else {
// “代删除”节点的父节点为靶节点,此时置y为父节点
x_parent = y;
}
// 将补位的“待删除”节点与靶节点的父节点简建立关联
// a. 父对子
if (root == z)
root = y;
else if (z->parent()->left == z)
z->parent()->left = y;
else
z->parent()->right = y;
// b. 子对父
y->setParent(z->parent());
// Swap the colors(交换颜色)
// 推导:此时z保存的是y的原始颜色,该颜色对后续的平衡处理有影响
QMapNodeBase::Color c = y->color();
y->setColor(z->color());
z->setColor(c);
y = z;
// 2.2 顶替节点与删除节点相同
} else {
// 比较简单,就是单侧节点的上移,更新父子关系
x_parent = y->parent();
if (x)
x->setParent(y->parent());
if (root == z)
root = x;
else if (z->parent()->left == z)
z->parent()->left = x;
else
z->parent()->right = x;
}
// 3. “代删除”节点为黑色节点,需要做平衡处理:判断“代删除”节点的兄弟节点的颜色状态,做换色或者旋转处理
if (y->color() != QMapNodeBase::Red) {
//3.1 补位节点为黑色
while (x != root && (x == 0 || x->color() == QMapNodeBase::Black)) {
//3.1.1 “代删除” 节点的父节点为左侧节点
if (x == x_parent->left) {
QMapNodeBase *w = x_parent->right;
//a. 场景1:右侧节点为红色,则其子节点必为黑色,左侧旋转,交互颜色后,变为场景2
if (w->color() == QMapNodeBase::Red) {
w->setColor(QMapNodeBase::Black);
x_parent->setColor(QMapNodeBase::Red);
rotateLeft(x_parent);
w = x_parent->right;
}
//b. 场景2:右侧兄弟节点的左右子节点均为黑黑色,将右兄弟节点置为红色,树的高度整体减一,由父节点去做平衡调整
if ((w->left == 0 || w->left->color() == QMapNodeBase::Black) &&
(w->right == 0 || w->right->color() == QMapNodeBase::Black)) {
w->setColor(QMapNodeBase::Red);
x = x_parent;
x_parent = x_parent->parent();
//!!!该处无break,由父节点继续做判断调整
//c. 场景3:右侧兄弟节点的左、右子节之一点为红色
} else {
//场景3-1:左侧节点为红色
if (w->right == 0 || w->right->color() == QMapNodeBase::Black) {
// 交换颜色,并以w为中心做右旋,转换为场景3-2
if (w->left)
w->left->setColor(QMapNodeBase::Black);
w->setColor(QMapNodeBase::Red);
rotateRight(w);
w = x_parent->right;
}
//场景3-2:右侧节点为红色,交换颜色并左旋,完成平衡
w->setColor(x_parent->color());
x_parent->setColor(QMapNodeBase::Black);
if (w->right)
w->right->setColor(QMapNodeBase::Black);
rotateLeft(x_parent);
break;
}
//3.1.2 “代删除”节点为右侧节点,逻辑处理同左侧
} else {
QMapNodeBase *w = x_parent->left;
if (w->color() == QMapNodeBase::Red) {
w->setColor(QMapNodeBase::Black);
x_parent->setColor(QMapNodeBase::Red);
rotateRight(x_parent);
w = x_parent->left;
}
if ((w->right == 0 || w->right->color() == QMapNodeBase::Black) &&
(w->left == 0 || w->left->color() == QMapNodeBase::Black)) {
w->setColor(QMapNodeBase::Red);
x = x_parent;
x_parent = x_parent->parent();
} else {
if (w->left == 0 || w->left->color() == QMapNodeBase::Black) {
if (w->right)
w->right->setColor(QMapNodeBase::Black);
w->setColor(QMapNodeBase::Red);
rotateLeft(w);
w = x_parent->left;
}
w->setColor(x_parent->color());
x_parent->setColor(QMapNodeBase::Black);
if (w->left)
w->left->setColor(QMapNodeBase::Black);
rotateRight(x_parent);
break;
}
}
}
// 3.2 补位节点为红色,补位后直接变为红色即可
if (x)
x->setColor(QMapNodeBase::Black);
}
// 3.3 y已经移出树结构,所以将其释放
free(y);
--size;
}
// 更新最左侧节点
void QMapDataBase::recalcMostLeftNode()
{
mostLeftNode = &header;
while (mostLeftNode->left)
mostLeftNode = mostLeftNode->left;
}
static inline int qMapAlignmentThreshold()
{
// malloc on 32-bit platforms should return pointers that are 8-byte
// aligned or more while on 64-bit platforms they should be 16-byte aligned
// or more
return 2 * sizeof(void*);
}
static inline void *qMapAllocate(int alloc, int alignment)
{
return alignment > qMapAlignmentThreshold()
? qMallocAligned(alloc, alignment)
: ::malloc(alloc);
}
static inline void qMapDeallocate(QMapNodeBase *node, int alignment)
{
if (alignment > qMapAlignmentThreshold())
qFreeAligned(node);
else
::free(node);
}
// 新增节点,挂在到指定父节点的左侧或右侧分支下
QMapNodeBase *QMapDataBase::createNode(int alloc, int alignment, QMapNodeBase *parent, bool left)
{
QMapNodeBase *node = static_cast<QMapNodeBase *>(qMapAllocate(alloc, alignment));
Q_CHECK_PTR(node);
memset(node, 0, alloc);
++size;
if (parent) {
if (left) {
parent->left = node;
if (parent == mostLeftNode)
mostLeftNode = node;
} else {
parent->right = node;
}
node->setParent(parent);
rebalance(node);
}
return node;
}
// 递归析构正树结构,先左侧后右侧
void QMapDataBase::freeTree(QMapNodeBase *root, int alignment)
{
if (root->left)
freeTree(root->left, alignment);
if (root->right)
freeTree(root->right, alignment);
qMapDeallocate(root, alignment);
}
QMapDataBase *QMapDataBase::createData()
{
QMapDataBase *d = new QMapDataBase;
d->ref.initializeOwned();
d->size = 0;
d->header.p = 0; // 节点数据
d->header.left = 0; // 左侧节点
d->header.right = 0; // 右侧节点
d->mostLeftNode = &(d->header);
return d;
}
void QMapDataBase::freeData(QMapDataBase *d)
{
delete d;
}