红黑树的应用与实现
就是给自己做个笔记的,讲的很不清楚,想彻底弄懂红黑树推荐这篇博客:红黑树
应用
- stl中map
- niginx、epoll
- 定时器
- cfs:进程调度时查找最小调度事件
- 内存管理:以内存起始地址作为key,加速内存块查找
利用红黑树的两个利用点:
- key,value查找
- 中序遍历是顺序
实现
红黑树的五个性质:
这五个性质保证了左右子树的高度不超过2倍,如果一颗子树的高度是n,另一棵子树的最大高度最大是2n-1
旋转
旋转分为左旋和右旋
和avl树的选择一样的,首先进行节点的上下互换,然后左旋后,下面的节点在左边;右旋后,下面的节点在右边
旋转是基础,因为在插入和删除后的修复,都需要用到旋转操作,这里只进行插入
代码实现:不包含删除
// 着色是为了保证每条路径上黑高相同,保持相对的平衡
#define RED 0
#define BLACK 1
// 红黑树的两个利用点:查找快;中序遍历是顺序的
typedef int KEY_TYPE; // 方便把key_compare(a,b)这个接口留出来
// 红黑树节点
typedef struct _rbtree_node {
//rbtree
unsigned char color;
struct _rbtree_node *left;
struct _rbtree_node *right;
struct _rbtree_node *parent; // 旋转的时候要用到
// end
KEY_TYPE key;
void *value;
// value
} rbtree_node;
// 红黑树
typedef struct _rbtree {
rbtree_node *root;
rbtree_node *nil; // 通用的叶子节点
}rbtree;
// 左旋:旋转都是以父节点为标准的
void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
// NULL --> T->nil
if (x == T->nil) return ;
// 1
rbtree_node *y = x->right;
x->right = y->left;
if (y->left != T->nil) {
y->left->parent = x;
}
// 2
y->parent = x->parent;
if (x->parent == T->nil) { // 如果x就是root节点
T->root = y;
} else if (x == x->parent->left) { // x是左子节点
x->parent->left = y;
} else {
x->parent->right = y; // x是右子节点
}
// 3
y->left = x;
x->parent = y;
}
// 把左旋中的x和y,right和left互改就行了
void rbtree_right_rotate(rbtree *T, rbtree_node *y) {
// NULL --> T->nil
if (y == T->nil) return ;
// 1
rbtree_node *x = y->left;
y->left = x->right;
if (x->right != T->nil) {
x->right->parent = y;
}
// 2
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;
}
// 3
x->right = y;
y->parent = x;
}
// 节点插入
// 小往左,大往右
void rbtree_insert(rbtree *T, rbtree_node *z) {
rbtree_node *y = T->nil;
rbtree_node *x = T->root;
while (x != T->nil) { // 找到节点添加的位置x
y = x; // y是x的父节点,也就是将要插入的节点z的父节点
if (z->key < x->key) { // 这里可以用 key_compare(a,b)接口
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 (z->key < y->key) {
y->left = z;
} else {
y->right = z;
}
// 着色:红,如果着色是黑色的话,第五条性质不好判断
z->color = RED;
z->left = T->nil;
z->right = T->nil;
}
// 插入后修复:针对哪个节点修复,一共6种情况(3+3)
void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {
// z节点和其父节点是红色的,且父节点是左子树(父为黑不需要调整) =》推定祖父节点是黑色的,但叔父节点可能是红或者黑
/*
1.叔父节点是红色
2.叔父节点是黑色,z是左子树
3.叔父节点是黑色,z是右子树
*/
while (z->parent->color == RED) { //
if (z->parent == z->parent->parent->left) {
rbtree_node *y = z->parent->parent->right; // 叔父节点
if (y->color == RED) { // 叔父节点为红(和父节点同色,比较好处理):把父节点和叔父节点变黑,祖父节点变红
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent; // 祖父节点可能和它的父节点冲突了,继续处理祖父节点(而且能保证z一直是红色的)
} else { // 叔父节点为黑
if (z = z->parent->right) { // z是右子树
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{ // 另外三种情况:如果父节点是右子树 => 把上面的代码拷贝下来,left改成right就行
rbtree_node *y = z->parent->parent->left; // 叔父节点
if (y->color == RED) { // 叔父节点为红(和父节点同色,比较好处理):把父节点和叔父节点变黑,祖父节点变红
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent; // 祖父节点可能和它的父节点冲突了,继续处理祖父节点(而且能保证z一直是红色的)
} else { // 叔父节点为黑
if (z = z->parent->left) { // z是左子树
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;
}