红黑树:
性质:
1、每个节点是红的或者黑的
2、根节点是黑的
3、每个叶子节点是黑的
4、如果一个节点是红的,则它两个孩子都是黑的
5、对每个节点,从该节点到其子孙节点的所有路径上的包含相同数目的黑节点
6、每个叶子节点都隐藏,并且为黑色
应用:
1、Linux进程调度CFS
2、Nginx Timer事件管理
3、Epoll事件块的管理
红黑树:
数据结构:
typedef int KEY_TYPE;
typedef struct _rbtree_node
{
unsigned char color;
struct _rbtree_node *right;
struct _rbtree_node *left;
struct _rbtree_node *parent;
KEY_TYPE key;
void *value;
}rbtree_node;
typedef struct _rbtree
{
rbtree_node *root;
rbtree_node *nil;
}rbtree;
红黑树结点旋转:
//红黑树的旋转
//左旋
void rbtree_left_rotate(rbtree *T, rbtree_node *x)
{
rbtree_node *y = x->right; //将x的右子树赋值给y做第一步旋转
x->right = y->left; //1、x的右子树等于y的左子树
if(y->left != T->nil) //2、如果y的左子树不是叶子节点则y的左子树的父节点是x
{
y->left->parent = x;
}
y->parent = x->parent; //3、y的父节点等于x的父节点
if(x->parent == T->nil) //4、判断x是否位为根节点
{
T->root = y;
}
else if(x == x->parent->left)
{
x->parent->left = y;
}
else
{
x->parent->right = y;
}
y->left = x; //5、最后拼接将y的左子树赋给x,x的父节点赋给y,完成旋转
x->parent = y;
}
//右旋与左旋同理
void rbtree_right_rotate(rbtree *T, rbtree_node *y)
{
rbtree_node *x = y->left;
y->left = x->right;
if(x->right != T->nil)
{
x->right->parent = y;
}
x->parent = y->parent;
if(y->parent == T->nil)
{
T->root = x;
}
else if(y == y->parent->right)
{
y->parent->right = x;
}
else
{
y->parent->left = x;
}
x->right = y;
y->parent = x;
}
红黑树的插入及其插入后的位置修正:
1、当前新插入节点node是红色的,node的父节点是红色,node的祖父节点肯定是黑色的,叔父节点可能是红色也可能是黑色
2、当前节点永远是红色的
3、当叔父节点是红色时不需要旋转,只改变颜色(叔父节点和父节点黑色高度一样)
4、当叔父节点是黑色时且当前节点是右子树,左旋
5、当叔父节点是黑色时且当前节点是左子树,右旋
//插入后的修复
void rbtree_insert_fix(rbtree *T, rbtree_node *node)
{
while(node->parent->color == RED)
{
if(node->parent == node->parent->parent->left)
{
//当node的父节点是右子树时
rbtree_node *uncle_node = node->parent->parent->right;
if(uncle_node->color == RED)
{
node->parent->color = BLACK;
uncle_node->color = BLACK;
node->parent->parent->color = RED;
node = node->parent->parent;
}
else
{
//叔父节点是黑色时且为右子树,左旋
if(node == node->parent->right)
{
node = node->parent;
rbtree_left_rotate(T, node);
}
//叔父节点是黑色时且为左子树,右旋
node->parent->color = BLACK;
node->parent->parent->color = RED;
rbtree_right_rotate(T, node->parent->parent);
}
}
else
{
//当node的父节点是左子树时
rbtree_node *uncle_node = node->parent->parent->left;
if(uncle_node->color == RED)
{
node->parent->color = BLACK;
uncle_node->color = BLACK;
node->parent->parent->color = RED;
node = node->parent->parent;
}
else
{
if(node == node->parent->left)
{
node = node->parent;
rbtree_right_rotate(T, node);
}
node->parent->color = BLACK;
node->parent->parent->color = RED;
rbtree_left_rotate(T, node->parent->parent);
}
}
}
T->root->color = BLACK;
}
//红黑树的插入
void rbtree_insert(rbtree *T, rbtree_node *node)
{
rbtree_node *y = T->nil;
rbtree_node *x = T->root;
while(x != T->nil) //x循环到叶子节点
{
y = x;
if(node->key < x->key)
{
x = x->left;
}
else if(node->key > x->key)
{
x = x->right;
}
else
{
return ;
}
}
node->parent = y;
if(y == T->nil)
{
T->root = node; //只有一个节点时新插入节点就是根节点
}
else if(node->key < y->key)
{
y->left = node;
}
else
{
y->right = node;
}
node->left = T->nil;
node->right = T->nil;
node->color = RED;
rbtree_insert_fix(T, node);
}
红黑树的删除:
如果删除节点27,则172是覆盖节点,206是删除节点,224是轴心节点
1、如果要删除的节点node没有左右子树直接将该节点删除
2、node节点有左子树或者右子树,将node节点转移到其父节点上,把node节点删除
3、node节点有左子树且有右子树则需分多种情况讨论(y为黑色,x是y的右子树。如果x是红色,则把x赋为黑色,反之则进行调整)
a、当前节点的兄弟节点是红色的
b、当前节点的兄弟节点是黑色的,而且兄弟节点的两个孩子节点都是黑色的
c、当前节点的兄弟节点是黑色的,而且兄弟节点的左孩子是红色的,右孩子是黑色的
d、当前节点的兄弟节点是黑色的,而且兄弟节点的右孩子是红色的
//找最小节点
rbtree_node *rbtree_mini(rbtree *T, rbtree_node *node)
{
while(node->left != T->nil)
{
node = node->left;
}
return node;
}
//找最大节点
rbtree_node *rbtree_max(rbtree *T, rbtree_node *node)
{
while(node->right != T->nil)
{
node = node->right;
}
return node;
}
//寻找继承节点
rbtree_node *rbtree_successor(rbtree *T, rbtree_node *node)
{
rbtree_node *y = node->parent;
//分存在左右子树进行讨论
if(node->right != T->nil)
{
return rbtree_mini(T, node->right);
}
while((y != T->nil) && (node == y->right))
{
node = y;
y = y->parent;
}
return y;
}
//节点删除修复
void rbtree_delete_fix(rbtree *T, rbtree_node *x)
{
while((x != T->root) && (x->color == BLACK))
{
//判断x节点是否为左子树,是的话兄弟节点是右子树,反之则相反
if(x == x->parent->left)
{
rbtree_node *brother_node = x->parent->right;
if(brother_node->color == RED)
{
brother_node->color = BLACK;
x->parent->color = RED;
//如果兄弟节点是红色,则调整兄弟节点为黑色,父节点为红色,进行左旋
rbtree_left_rotate(T, x->parent);
brother_node = x->parent->right;
}
if((brother_node->left->color == BLACK) && (brother_node->right->color == BLACK))
{
brother_node->color = RED;
x = x->parent;
}
else
{
if(brother_node->right->color == BLACK)
{
//如果兄弟节点的右孩子是黑色,则调整其左孩子为黑色,自己则为红色,进行右旋
brother_node->left->color = BLACK;
brother_node->color = RED;
rbtree_right_rotate(T, brother_node);
brother_node = x->parent->right;
}
//反之调整其父节点为黑色,右孩子为黑色,自身为父节点颜色,左旋
brother_node->color = x->parent->color;
x->parent->color = BLACK;
brother_node->right->color = BLACK;
rbtree_left_rotate(T, x->parent);
x = T->root;
}
}
else
{
//x节点是右子树时,与上同理
rbtree_node *brother_node = x->parent->left;
if(brother_node->color == RED)
{
brother_node->color = BLACK;
x->parent->color = RED;
rbtree_right_rotate(T, x->parent);
brother_node = x->parent->left;
}
if((brother_node->left->color == BLACK) && (brother_node->right->color == BLACK))
{
brother_node->color = RED;
x = x->parent;
}
else
{
if(brother_node->left->color == BLACK)
{
brother_node->right->color == BLACK;
brother_node->color = RED;
rbtree_left_rotate(T, brother_node);
brother_node = x->parent->left;
}
brother_node->color = x->parent->color;
x->parent->color = BLACK;
brother_node->left->color = BLACK;
rbtree_right_rotate(T, x->parent);
x = T->root;
}
}
}
x->color = BLACK;
}
//红黑树节点删除
rbtree_node *rbtree_delete(rbtree *T, rbtree_node *node)
{
rbtree_node *y = T->nil;
rbtree_node *x = T->nil;
//判断node是否有左子树或右子树
if((node->left == T->nil) || (node->right == T->nil))
{
y = node;
}
else
{
y = rbtree_successor(T, node); //寻找继承节点
}
//转移节点
if(y->left != T->nil)
{
x = y->left;
}
else if(y->right != T->nil)
{
x = y->right;
}
x->parent = y->parent;
if(y->parent == T->nil)
{
T->root = x;
}
else if(y == y->parent->left)
{
y->parent->left = x;
}
else
{
y->parent->right = x;
}
if(y != node)
{
node->key = y->key;
node->value = y->value;
}
//如果当前节点是黑色即要保持黑高则要进行修复
if(y->color == BLACK)
{
rbtree_delete_fix(T, x);
}
return y;
}