红黑树的性质:
- 每个结点是红色或者黑色
- 根结点是黑色的
- 每个叶子节点是黑色的
- 如果一个结点红色的,则它的两个儿子都是黑色的
- 对每个结点,从该结点到其子孙结点的所有路径上的包含相同数目的黑结点。(红黑树的平衡,黑高!)
?
?
红黑树的用处:
- map-->
- nginx-->
- 定时器
- cfs(进程的调度)
- 内存管理 (key -->起始位置 +value -->长度)
? ? ? ? ?块内存管理的两种表示方法:1. 起始位置+长度;2.开始位置+结束位置
?红黑树的使用情况:
- key, value --> 查找
- 中序遍历是顺序的。(例cfs, 查找速度快且有序)
红黑树的实现:
1. 结点的定义:
typedef int KEY_TYPE;
//六点属性,颜色、左子树、右子树、父亲、key /value
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;
2. 红黑树定义:?
typedef struct _rbtree {
rbtree_node *root;
rbtree_node *nil; // 通用的叶子结点,所有的也叶子结点都指向同一个位置
} rbtree;
1、2完成就完成红黑树的轮廓?
3. 红黑树的结点旋转:
?三个方向六个指针
左旋代码:
void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
rbtree_node *y = x->right; // x --> y , y --> x, right --> left, left --> right
x->right = y->left; //1 1
if (y->left != T->nil) { //1 2
y->left->parent = x;
}
y->parent = x->parent; //1 3
if (x->parent == T->nil) { //1 4
T->root = y;
} else if (x == x->parent->left) {
x->parent->left = y;
} else {
x->parent->right = y;
}
y->left = x; //1 5
x->parent = y; //1 6
}
右旋把左旋的 x-->y , y-->x, left-->right, right-->left? 代码如下:
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;
}
4. 红黑树的插入:
//两个参数:1. 插入那棵树;2. 插入的结点
void rbtree_insert(rbtree *T, rbtree_node *z) {
rbtree_node *y = T->nil;
rbtree_node *x = T->root;
while (x != T->nil) {
y = x; //保持 y 是 x 的父结点
if (z->key < x->key) {
x = x->left;
//可以单独做一个函数key_compare(KEY_TYPE* a, KEY_TYPE* a),红黑树可做成模板。
} else if (z->key > x->key) {
x = x->right;
} else { //Exist
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->left = T->nil;
z->right = T->nil;
z->color = RED;
rbtree_insert_fixup(T, z); //插入修复
}
5. 红黑树的修复:?
大的前提:插入当前节点前就是红黑树!!要不要牵扯到祖父节点的颜色。黑色
- 当前节点是红色
- 父节点是红色
- -->推断祖父节点是黑色
-->叔父节点是红色或者黑色
?
void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {
//while 递归向上直到根节点
while (z->parent->color == RED) { //z ---> RED
if (z->parent == z->parent->parent->left) {
rbtree_node *y = z->parent->parent->right; //y 是叔父节点
if (y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent; //z --> RED
} 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) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent; //z --> RED
} 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; //始终将根节点置为黑色
}
|