一、红黑树的特性
1.每个节点都是红的或者黑的;
2.根节点是黑色;
3.每个叶子节点都是黑色(度为0的节点为叶子节点);
4.如果一个节点是红色,则他的两个子节点为黑色;
5.对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点。
二、红黑树的使用场景
红黑树主要是通过其<key, value>特性及其中序遍历的特性来针对不同场景进行使用的。以下是红黑树的几个使用场景(先大概总结,待后续把每个点深入学习以后进行分析总结):
1.C++标准库中的STL map容器内部使用了红黑树的数据结构,对红黑树进行了封装实现;
2.nginx定时器timer
3.Linux进程调度cfs
4.Linux内存管理
5.epoll事件管理
三、红黑树的实现
1.红黑树及其节点定义:
#define RED 0
#define BLACK 1
typedef int KET_TYPE;
typedef struct _rb_tree_node
{
unsigned char color;
struct _rb_tree_node* left;
struct _rb_tree_node* right;
struct _rb_tree_node* parent;
/* data */
KET_TYPE key;
void* value;
}rbtree_node;
typedef struct _rbtree
{
/* data */
_rb_tree_node *root;
_rb_tree_node *nil; //NULL
}rbtree;
2.红黑树节点的左旋:
void left_rotate(rbtree* T, rbtree_node *x)
{
//参数判断
if (x == T->nil)
return;
rbtree_node *y = x->right;
//x的右节点指向y的左节点,y的左节点如果不为空,则其父节点指向x
x->right = y->left;
if (y->left != T->nil)
{
y->left->parent = x;
}
//x的父节点指向y
y->parent = x->parent;
if (x->parent == T->nil)
{
T->root = y;
}
else if (x->parent->left == x)
{
x->parent->left = y;
}
else if (x->parent->right == x)
{
x->parent->right = y;
}
//y的左节点指向x
y->left = x;
x->parent = y;
}
3.红黑树节点的右旋:
void right_rotate(rbtree* T, rbtree_node *y)
{
//参数判断
if (y == T->nil)
return;
rbtree_node *x = y->left;
//y的左节点指向x的右节点,x的右节点如果不为空,则其父节点指向y
y->left = x->right;
if (x->right != T->nil)
{
x->right->parent = y;
}
//y的父节点指向x
x->parent = y->parent;
if (y->parent == T->nil)
{
T->root = x;
}
else if (y->parent->right == y)
{
y->parent->right = x;
}
else if (y->parent->left == y)
{
y->parent->left = x;
}
//x的右节点指向y
x->right = y;
y->parent = x;
}
4.红黑树节点的插入:
void rbtree_insert(rbtree* T, rbtree_node* z)
{
rbtree_node* y = T->nil;
rbtree_node* x = T->root;
while (x != T->nil)
{
y = x;
if (z->key < x->key)
{
x = x->left;
}
else if (z->key > x->key)
{
x = x->right;
}
else
{
//相等的清空根据实际业务,可做处理或不做处理
}
}
//遍历结束后,此时已确定要插入节点的位置
z->parent = y;
if (y == T->nil)
{
T->root = z;
}
else if (z->key > y->key)
{
y->left = z;
}
else if (z->key < y->key)
{
y->right = z;
}
//默认新插入节点的颜色为红色
z->color = RED;
z->left = T->nil;
z->right = T->nil;
}
5.红黑树节点的平衡修复:
默认当前T为红黑树,插入的节点默认为红色,分情况讨论:
1.如果当前节点的父节点为祖父节点的左节点:
①如果当前叔父节点为红色;
②如果当前叔父节点为黑色;
2.如果当前节点的父节点为祖父节点的右节点(待完善):
void rbtree_insert_fixup(rbtree* T, rbtree_node* z)
{
rbtree_node* y = T->nil;
while (z->color == RED)
{
if (z->parent == z->parent->parent->left)
{
y = z->parent->parent->right;
//如果叔父节点是红色
if (y->color == RED)
{
//父节点变红,祖父节点变黑,叔父节点变红
z->parent->color = RED;
z->parent->parent->color = BLACK;
y->color = RED;
//祖父节点指向当前节点
z = z->parent->parent;
}
else
{
if (z = z->parent->right)
{
z = z->parent;
left_rotate(T, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
right_rotate(T, z->parent->parent);
}
}
else if (z->parent == z->parent->parent->right)
{
//待完善
}
}
}
6.红黑树节点的删除(待完善):