C++后端开发(1.1.1)——数据结构之红黑树
小节提纲
1 红黑树定义
2 红黑树性质
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
一颗红黑树如下图所示
3 红黑树用途和好处
4.红黑树C代码实现
4.1 结构体
根据红黑树的性质进行红黑树结构体的定义
#define RED 1
#define BLACK 2
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; // 所有叶子节点指向nil,通用的叶子节点
} rbtree;
4.2 找到最小与找到最大
// 找到最小
rbtree_node *rbtree_mini(rbtree *T, rbtree_node *x)
{
while (x->left != T->nil)
{
x = x->left;
}
return x;
}
// 找到最大
rbtree_node *rbtree_maxi(rbtree *T, rbtree_node *x)
{
while (x->right != T->nil)
{
x = x->right;
}
return x;
}
4.3 红黑树左旋与右旋
4.3.1 仅旋转
4.3.2 旋转后上色
4.3.3 左旋
// 左旋
void rbtree_left_rotate(rbtree *T, rbtree_node *x)
{
// x --> y , y --> x, right --> left, left --> right
rbtree_node *y = x->right;
x->right = y->left;
// y的左子树不是叶子节点
if (y->left != T->nil)
{
y->left->parent = x;
}
y->parent = x->parent;
// 确定 y 是根节点还是左子树还是右子树
if (x->parent == T->nil)
{
T->root = y;
}
else if (x == x->parent->left)
{
x->parent->left = y;
}
else
{
x->parent->right = y;
}
// 重新连接x和y
y->left = x;
x->parent = y;
}
4.3.4 右旋
// 右旋(把左旋中的x和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;
}
4.4 红黑树插入节点
4.4.1 插入
// 插入
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
{
// 已经存在
return;
}
}
// 确定z是y的左子树还是右子树
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);
}
4.4.2 插入调整
父结点是祖父结点的左子树的情况
-
叔结点是红色的
-
叔结点是黑色的,而且当前结点是右孩子
-
叔结点是黑色的,而且当前结点是左孩子
// 插入补充
// 父结点是祖父结点的左子树的情况
// 1. 叔结点是红色的
// 2. 叔结点是黑色的,而且当前结点是右孩子
// 3. 叔结点是黑色的,而且当前结点是左孩子
void rbtree_insert_fixup(rbtree *T, rbtree_node *z)
{
while (z->parent->color == RED)
{
// z ---> 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;
}
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;
}
4.5 红黑树删除节点
4.5.0 删除知识点补充
什么是覆盖节点? z 需要拿y换掉
什么是删除节点? y 用于替换z
什么是轴心节点? x
4.5.1 删除节点(先不考虑颜色)
-
没有左右子树
-
有左子树或者右子树
-
有左子树且有右子树
rbtree_node *rbtree_delete(rbtree *T, rbtree_node *z)
{
rbtree_node *y = T->nil;
rbtree_node *x = T->nil;
// 先找替换用的节点y
// 1.没有左右子树
// 2.有左子树或右子树
if ((z->left == T->nil) || (z->right == T->nil))
{
y = z;
}
// 3.有左子树且有右子树
else
{
y = rbtree_successor(T, z);
}
//补充y被换走以后的位置
if (y->left != T->nil)
{
x = y->left;
}
else if (y->right != T->nil)
{
x = y->right;
}
// 在把y换走之前先把坑补上
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;
}
// 把y换到z的位置上
if (y != z)
{
z->key = y->key;
z->value = y->value;
}
if (y->color == BLACK)
{
rbtree_delete_fixup(T, x);
}
return y;
}
4.5.2 删除节点后调整
当前结点是父结点的左子树的情况
5. 当前结点的兄弟结点是红色的
- 当前结点的兄弟结点是黑色的,而且兄弟结点的两个孩子结点都是黑色的
- 当前结点的兄弟结点是黑色的,而且兄弟结点的左孩子是红色的,右孩子是黑色的当前结点是父结点的左子树的情况
- 当前结点的兄弟结点是黑色的,而且兄弟结点的右孩子是红色的
//找到最接近的左子树
rbtree_node *rbtree_successor(rbtree *T, rbtree_node *x)
{
rbtree_node *y = x->parent;
// 如果x不是叶子节点,则返回的x右子树的最小值
if (x->right != T->nil)
{
return rbtree_mini(T, x->right);
}
while ((y != T->nil) && (x == y->right))
{
x = y;
y = y->parent;
}
return y;
}
// 删除补充
// 当前结点是父结点的左子树的情况
// 1. 当前结点的兄弟结点是红色的
// 2. 当前结点的兄弟结点是黑色的,而且兄弟结点的
// 两个孩子结点都是黑色的
// 3. 当前结点的兄弟结点是黑色的,而且兄弟结点的
// 左孩子是红色的,右孩子是黑色的
// 当前结点是父结点的左子树的情况
// 4. 当前结点的兄弟结点是黑色的,而且兄弟结点的
// 右孩子是红色的
void rbtree_delete_fixup(rbtree *T, rbtree_node *x)
{
while ((x != T->root) && (x->color == BLACK))
{
if (x == x->parent->left)
{
rbtree_node *w = x->parent->right;
if (w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
rbtree_left_rotate(T, x->parent);
w = x->parent->right;
}
if ((w->left->color == BLACK) && (w->right->color == BLACK))
{
w->color = RED;
x = x->parent;
}
else
{
if (w->right->color == BLACK)
{
w->left->color = BLACK;
w->color = RED;
rbtree_right_rotate(T, w);
w = x->parent->right;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->right->color = BLACK;
rbtree_left_rotate(T, x->parent);
x = T->root;
}
}
else
{
rbtree_node *w = x->parent->left;
if (w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
rbtree_right_rotate(T, x->parent);
w = x->parent->left;
}
if ((w->left->color == BLACK) && (w->right->color == BLACK))
{
w->color = RED;
x = x->parent;
}
else
{
if (w->left->color == BLACK)
{
w->right->color = BLACK;
w->color = RED;
rbtree_left_rotate(T, w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
rbtree_right_rotate(T, x->parent);
x = T->root;
}
}
}
x->color = BLACK;
}
4.6 查找
// 查找
rbtree_node *rbtree_search(rbtree *T, KEY_TYPE key)
{
rbtree_node *node = T->root;
while (node != T->nil)
{
if (key < node->key)
{
node = node->left;
}
else if (key > node->key)
{
node = node->right;
}
else
{
return node;
}
}
return T->nil;
}
4.7 中序遍历
// 用递归实现中序遍历
void rbtree_traversal(rbtree *T, rbtree_node *node)
{
if (node != T->nil)
{
rbtree_traversal(T, node->left);
printf("key:%d, color:%d\n", node->key, node->color);
rbtree_traversal(T, node->right);
}
}
4.8 主函数
int main()
{
int keyArray[20] = {24, 25, 13, 35, 23, 26, 67, 47, 38, 98, 20, 19, 17, 49, 12, 21, 9, 18, 14, 15};
rbtree *T = (rbtree *)malloc(sizeof(rbtree));
if (T == NULL)
{
printf("malloc failed\n");
return -1;
}
T->nil = (rbtree_node *)malloc(sizeof(rbtree_node));
T->nil->color = BLACK;
T->root = T->nil;
rbtree_node *node = T->nil;
int i = 0;
for (i = 0; i < 20; i++)
{
node = (rbtree_node *)malloc(sizeof(rbtree_node));
node->key = keyArray[i];
node->value = NULL;
rbtree_insert(T, node);
}
rbtree_traversal(T, T->root);
printf("----------------------------------------\n");
for (i = 0; i < 20; i++)
{
rbtree_node *node = rbtree_search(T, keyArray[i]);
rbtree_node *cur = rbtree_delete(T, node);
free(cur);
rbtree_traversal(T, T->root);
printf("----------------------------------------\n");
}
return 0;
}
红黑树代码