红黑树的插入操作
Posted 涨点姿势吧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了红黑树的插入操作相关的知识,希望对你有一定的参考价值。
一,红黑树的五个性质:
1,每个结点为红色或者为黑色。
2,根结点为黑色
3,叶子结点为黑色
4,红色结点的两个儿子结点为黑色
5,对于每个结点,它的每条路径上有相同数目的黑色结点。
二,数据结构:
typedef int KEY_TYPE;
typedef struct _rbtree_node{
unsigned char color;
KEY_TYPE key;
struct rbtree_node* left;
struct rbtree_node* right;
struct rbtree_node* parent;
}rbtree_node;
typedef struct _rbtree{
struct _rbtree_node* root;
struct _rbtree_node* nil;
}rbtree;
三、开始操作
我们假设插入结点为Z,红色,并将其插入到红黑树中了(先预设,当前结点Z的父结点为祖父结点的左孩子,那么当前结点Z的叔结点为祖父结点的右孩子)
现需要调整,调整有以下几种情况:
父结点是黑色。(啥也不用管)
父结点是红色(祖父节点肯定是黑色的,因为性质4)
叔结点是红色的。此时需要变色。把父结点和叔结点都变为黑色。把祖父结点变为红色。继续判断祖父结点是否满足红黑树性质。
叔结点是黑色的,此时需要判断,父结点需要不需要旋转。然后改变父结点的颜色为黑色、改变祖父结点的颜色为红色,旋转祖父结点。
一),父结点是黑色。
如下图,插入一个814结点,其父结点就是黑色的。满足红黑树性质。
二)、父结点是红色的,叔父结点也是红色的。调整时仅仅需要变色:
当前节点:11
当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色
(01) 将“父节点”设为黑色
(02) 将“叔叔节点”设为黑色
(03) 将“祖父节点”设为“红色
(04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作
三)、父结点是红色的,叔父结点是黑色的,调整分为两种:
第一种调整:
当前节点:670
当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子
(01) 将“父节点”设为“黑色”
(02) 将“祖父节点”设为“红色”
(03) 以“祖父节点”为支点进行右旋
第二种调整:
当前节点:675
当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子
(01) 将“父节点”作为“新的当前节点”
(02) 以“新的当前节点”为支点进行左旋
此时回到了第一种调整的样子,按照第一种调整方式来处理即可。
因此我们有以下思路:
1,插入结点Z到红黑树中,Z为当前结点,红色。
2,开始调整:当父结点是红色时
如果父结点为祖父结点的左孩子
叔结点为红色,变色处理。将父结点和叔结点变为黑色。把祖父结点变为红色。将祖父结点作为当前结点,继续循环2。
叔结点为黑色,判断当前结点Z是父结点的左孩子还是右孩子
如果是右孩子,则以父结点为中心左旋。变为 "长链 / "。
改变父结点为黑色,祖父结点为红色。再以祖父结点为中心右旋。继续循环2。
如果父结点为祖父结点的右孩子
叔结点为红色,变色处理。将父结点和叔结点变为黑色。把祖父结点变为红色。将祖父结点作为当前结点,继续循环2.
叔结点为红色,判断当前结点Z是父结点的左孩子还是右孩子,如果是左孩子,则以父结点为中心右旋,变为“长链 ”。
改变父结点为黑色,祖父结点为红色。再以祖父结点为中心左旋。继续循环2。
代码如下:
void rbtree_insert_fixup(rbtree* T, rbtree_node* z)
{
//父结点为红色
while(z->parent->color == RED)
{
//父结点是祖父结点的左孩子
if(z->parent == z->parent->parent->left){
rbtree_node *y = z->parent->parent->right;
//叔结点为红色,需要变色,然后将祖父结点作为当前结点,继续循环
if(y->color == RED){
y->color = BLACK;
z->parent->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}else{
//叔结点为黑色
if(z == z->parent->right){
//当前结点是左孩子还是右孩子,如果是右孩子,需要先左旋,将其转化为"长链 /",
//即祖父结点的左孩子是父节点,父结点的左孩子是当前结点
z = z->parent;
rbtree_left_rotate(T,z);
}
//根据长链,变色,即改变父结点为黑色,祖父结点为红色,以祖父结点为中心,右旋。
z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_right_rotate(T,z->parent->parent);
}
}else{
rbtree_node* y = z->parent->parent->left;
if(y->color == RED)
{
y->color->BLACK;
z->parent->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}else{
if(z == z->parent->left){
z = z->parent;
rbtree_right_rotate(T,z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_left_rotate(T,z->parent->parent);
}
}
}
T->root->color = BLACK;
}
void rbtree_insert_node(rbtree* T,rbtree_node* z)
{
rbtree_node* x = T->root;
rbtree_node* y = T->nil;
while(x!=T->nil){
y = x;
if(z->key < x->key)
{
x = x->left;
}else if(z->key > x->key){
x = x->right;
}else{
return ;
}
}
z->parent = y;
if(y == T->nil){
T->root = z;
}else if(y->key > z->key){
y->left = z;
}else{
y->right = z;
}
z->color = RED;
z->left = T->nil;
z->right = T->nil;
rbtree_insert_fixup(T,z);
}
以上是关于红黑树的插入操作的主要内容,如果未能解决你的问题,请参考以下文章