一、数据结构
struct rb_node
{
struct rb_node *rb_parent;//父节点
struct rb_node *rb_right;//左孩子
struct rb_node *rb_left;//有孩子
char rb_color;
#define RB_RED 0
#define RB_BLACK 1
};
struct rb_root
{
struct rb_node *rb_node;
};
二、左旋和右旋
//左旋
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
{
//init/
struct rb_node *right = node->rb_right;
//第一步//
//如果该节点的孩子不为空,则更新该孩子的父节点
if ((node->rb_right = right->rb_left))
right->rb_left->rb_parent = node;
/第二步
right->rb_left = node;
//此时更新右旋后的右节点的父节点,如果存在父节点则更新node的父节点左或右孩子的指向
//如果不存在父节点则该节点为
if ((right->rb_parent = node->rb_parent))
{
//判断node是左孩子还是右孩子
if (node == node->rb_parent->rb_left)
node->rb_parent->rb_left = right;
else
node->rb_parent->rb_right = right;
}
else
root->rb_node = right;
//更新node父节点指针的指向
node->rb_parent = right;
}
//右旋
//逻辑和左旋一样,只不过反过来了
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
{
struct rb_node *left = node->rb_left;
if ((node->rb_left = left->rb_right))
left->rb_right->rb_parent = node;
left->rb_right = node;
if ((left->rb_parent = node->rb_parent))
{
if (node == node->rb_parent->rb_right)
node->rb_parent->rb_right = left;
else
node->rb_parent->rb_left = left;
}
else
root->rb_node = left;
node->rb_parent = left;
}
没做高低平衡处理,仅为理解代码用
图 init
第一步
第二步
三、插入结点后的调整
插入结点有一下几种情况
1、结点为根节点,直接插入
2、结点的父节点为黑色结点,可以直接插入,因为红色结点不会改变路径中的黑色结点数量,不会打破规则
3、父结点为红色,且舅舅结点也为红色,则需要调整结点颜色
4、如果都不满足则需要左旋活着右旋来调整
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent;
//判断条件:父节点存在 且 父节点为红色结点;插入结点必为红节点,一条路径上不能存在连个连续红结点
while ((parent = node->rb_parent) && parent->rb_color == RB_RED)
{
//祖父结点
gparent = parent->rb_parent;
//如果 父结点 是 祖父结点 的左孩子
if (parent == gparent->rb_left)
{
{
//情况3:舅舅结点存在 且 舅舅结点为红结点
//措施:红的变黑,黑的变红
//完成后更新祖父结点,跳过此次循环进入新循环,向上递归更新结点
register struct rb_node *uncle = gparent->rb_right;
if (uncle && uncle->rb_color == RB_RED)
{
uncle->rb_color = RB_BLACK;
parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
node = gparent;
continue;
}
}
//如果不存在舅舅结点,或者舅舅结点为黑色结点则不管,因为不会破坏舅舅结点下规则
//情况4:如果新插入结点为右结点;此时为两个连续红结点;
//平衡树失衡(左子树的右孩子导致:LR型),需要左旋然后右旋
//左旋完成后,调整指针指向,此时新插入的结点为之前父节点的父亲,并且调整颜色
if (parent->rb_right == node)
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
//此时旧父节点和祖父节点都为红结点,新结点为黑结点,通过一次右旋可变成父节点为黑结点,两个孩子结点为红结点
__rb_rotate_right(gparent, root);
//此时的node指针为最左,即第一个结点,父节点为黑色,不达成循环条件,跳出循环
} else {
//如果 父结点 是 祖父结点 的左孩子
{
//情况3.1:舅舅结点存在 且 舅舅结点为红结点
//措施:红的变黑,黑的变红
//完成后更新祖父结点,跳过此次循环进入新循环,向上递归更新结点
register struct rb_node *uncle = gparent->rb_left;
if (uncle && uncle->rb_color == RB_RED)
{
uncle->rb_color = RB_BLACK;
parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
node = gparent;
continue;
}
}
//如果不存在舅舅结点,或者舅舅结点为黑色结点则不管,因为不会破坏舅舅结点下规则
//情况4.1:如果新插入结点为左结点;此时为两个连续红结点;
//平衡树失衡(左子树的右孩子导致:RL型),需要右旋然后左旋
//右旋完成后,调整指针指向,此时新插入的结点为之前父节点的父亲,并且调整颜色
if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
parent->rb_color = RB_BLACK;
gparent->rb_color = RB_RED;
__rb_rotate_left(gparent, root);
}
}
//情况1:当为根结点时,不进入循环,直接插入,为根结点
//情况2:当父节点为黑结点时,不进入循环,直接插入;插入结点为红色,不会增加黑色结点,则不会破坏规则
root->rb_node->rb_color = RB_BLACK;
}
四、结点的删除
void rb_erase(struct rb_node *node, struct rb_root *root)
{
struct rb_node *child, *parent;
int color;
//情况1:如果删除的结点仅有左右孩子的的其中一个或是都没有,则直接跳过判断,与父结点进行连接
if (!node->rb_left)
child = node->rb_right;
else if (!node->rb_right)
child = node->rb_left;
else
{
//情况2:存在左右孩子结点
//措施:寻找比他大但比其他结点小的结点来取代他,即该结点的右孩子的最左结点
struct rb_node *old = node, *left;
node = node->rb_right;
while ((left = node->rb_left))//寻找最左孩子,并更新指针
node = left;
child = node->rb_right;
parent = node->rb_parent;
color = node->rb_color;
if (child)
child->rb_parent = parent;
//如果最左孩子存在右孩子,则将其父结点指针指向他的祖父结点
//后续将祖父结点与右孩子结点相连接,断开最左结点的连接
//判断是否为根节点,不是则和父结点连接,否则为根结点
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child;
if (node->rb_parent == old)
parent = node;
//替换两个结点
node->rb_parent = old->rb_parent;
node->rb_color = old->rb_color;
node->rb_right = old->rb_right;
node->rb_left = old->rb_left;
//更新旧结点的父节点指向
if (old->rb_parent)
{
if (old->rb_parent->rb_left == old)
old->rb_parent->rb_left = node;
else
old->rb_parent->rb_right = node;
} else
root->rb_node = node;
//将旧结点的左子树与node相连,自此old结点已离开红黑树
old->rb_left->rb_parent = node;
if (old->rb_right)
old->rb_right->rb_parent = node;
goto color;
}
//只有情况一才会运行到这
parent = node->rb_parent;
color = node->rb_color;
if (child)
child->rb_parent = parent;
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child;
color:
if (color == RB_BLACK)
__rb_erase_color(child, parent, root);
//在情况2下,child指向的是最初时删除结点的右孩子的最左结点的右孩子树
//通过调换结点,child前面的树的路径都没有受到变化,只有该孩子树的父结点受到了变化
//如果删除的结点为黑色,则调整红黑树的颜色
}
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
struct rb_root *root)
{
struct rb_node *other;
//判断条件:结点存在,且结点颜色为黑色
while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node)
{
//如果删除的结点为左结点
if (parent->rb_left == node)
{
other = parent->rb_right;
//如果存在兄弟结点,且为红色结点,进行左旋,变色,以此替代删掉的结点
//第一种情况,兄弟节点为红色结点,此时需要把兄弟结点改为黑色
if (other->rb_color == RB_RED)
{
other->rb_color = RB_BLACK;
parent->rb_color = RB_RED;
__rb_rotate_left(parent, root);
other = parent->rb_right;//更新兄弟结点
}
//第二种情况,兄弟节点为黑,且兄弟的俩孩子也都为黑色
//这种情况最好,兄弟结点分支多了一个black, 而且 brother 的两个儿子也是black,
//直接将兄弟结点改为红色结点.
//此时node和他的兄弟 黑色的个数一致了,但是,如果node的父亲是根,一切都很公平了,
//但是如果node的父亲不是根,node父亲这一脉,其实比node叔叔这一脉 少一个黑色节点。
//因此需要parent = node->rb_parent;来完成向上依次调整
if ((!other->rb_left ||
other->rb_left->rb_color == RB_BLACK)
&& (!other->rb_right ||
other->rb_right->rb_color == RB_BLACK))
{
other->rb_color = RB_RED;
node = parent;
parent = node->rb_parent;
}
else
{
//情况三,如果兄弟结点存在右孩子且为黑色结点,左孩子为红
//将兄弟结点的左孩子变黑,兄弟节点变红,右旋
//右旋完成后,左孩子变成兄弟结点,且变为第四种情况
if (!other->rb_right ||
other->rb_right->rb_color == RB_BLACK)
{
register struct rb_node *o_left;
if ((o_left = other->rb_left))//兄弟结点存在左孩子时,改变左孩子颜色
o_left->rb_color = RB_BLACK;
other->rb_color = RB_RED;
__rb_rotate_right(other, root);
other = parent->rb_right;//更新兄弟结点
}
//第四种情况,兄弟为黑,右孩子为红,
//兄弟继承父亲的颜色,父亲变为黑色,兄弟的右孩子变为黑色,左旋
other->rb_color = parent->rb_color;
parent->rb_color = RB_BLACK;
if (other->rb_right)
other->rb_right->rb_color = RB_BLACK;
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
//由此,兄弟这一分支的黑色个数没有减少,又因为父亲变成了黑色,node结点增加了一个黑色结点,由此达到平衡
}
}
else//反过来
{
other = parent->rb_left;
if (other->rb_color == RB_RED)
{
other->rb_color = RB_BLACK;
parent->rb_color = RB_RED;
__rb_rotate_right(parent, root);
other = parent->rb_left;
}
if ((!other->rb_left ||
other->rb_left->rb_color == RB_BLACK)
&& (!other->rb_right ||
other->rb_right->rb_color == RB_BLACK))
{
other->rb_color = RB_RED;
node = parent;
parent = node->rb_parent;
}
else
{
if (!other->rb_left ||
other->rb_left->rb_color == RB_BLACK)
{
register struct rb_node *o_right;
if ((o_right = other->rb_right))
o_right->rb_color = RB_BLACK;
other->rb_color = RB_RED;
__rb_rotate_left(other, root);
other = parent->rb_left;
}
other->rb_color = parent->rb_color;
parent->rb_color = RB_BLACK;
if (other->rb_left)
other->rb_left->rb_color = RB_BLACK;
__rb_rotate_right(parent, root);
node = root->rb_node;
break;
}
}
}
if (node)
node->rb_color = RB_BLACK;
}
五、其他
//逻辑和二叉排序树一样
//红黑树中的第一个结点,即最左结点
struct rb_node *rb_first(struct rb_root *root)
{
struct rb_node *n;
n = root->rb_node;
if (!n)
return (struct rb_node *)0;
while (n->rb_left)
n = n->rb_left;
return n;
}
//红黑树中的最后一个结点,即最右结点
struct rb_node *rb_last(struct rb_root *root)
{
struct rb_node *n;
n = root->rb_node;
if (!n)
return (struct rb_node *)0;
while (n->rb_right)
n = n->rb_right;
return n;
}
//下一个结点
struct rb_node *rb_next(struct rb_node *node)
{
//如果有右子树,则右子树的最左结点就是下个结点
if (node->rb_right) {
node = node->rb_right;
while (node->rb_left)
node = node->rb_left;
return node;
}
//找到一个处于某个父节点下的左子树的结点,其结点的父节点就是下一个结点
//右结点一定比父节点大
while (node->rb_parent && node == node->rb_parent->rb_right)
node = node->rb_parent;
return node->rb_parent;
}
//上一个结点
struct rb_node *rb_prev(struct rb_node *node)
{
//如果有左子树,左子树的最右结点就是上一个结点
if (node->rb_left) {
node = node->rb_left;
while (node->rb_right)
node = node->rb_right;
return node;
}
//左节点一定比父节点小,找到唯一那个右结点
while (node->rb_parent && node == node->rb_parent->rb_left)
node = node->rb_parent;
return node->rb_parent;
}
//替换结点
void rb_replace_node(struct rb_node *victim, struct rb_node *newnode,
struct rb_root *root)
{
struct rb_node *parent = victim->rb_parent;
if (parent) {
if (victim == parent->rb_left)
parent->rb_left = newnode;
else
parent->rb_right = newnode;
} else {
root->rb_node = newnode;
}
if (victim->rb_left)
victim->rb_left->rb_parent = newnode;
if (victim->rb_right)
victim->rb_right->rb_parent = newnode;
*newnode = *victim;
}
//插入新节点
static inline void rb_link_node(struct rb_node *node, struct rb_node *parent,
struct rb_node **link)
{
node->rb_parent = parent;
node->rb_color = RB_RED;
node->rb_left = node->rb_right = (struct rb_node *)0;
*link = node;
}