搞懂红黑树及其应用场景

红黑树

1 性质

1. 每个结点是红的或黑的
2. 根结点是黑的
3. 每个叶子结点是黑色的
4. 如果一个结点是红的,则它的两个儿子都是黑的(不能有连续两个红色结点)
5. 对每个结点,从该节点到其子孙结点的所有路径上的包含相同数目的黑结点

2 插入

  • 插入结点时默认是插入的红色结点,因为只有插入红色结点,在没调整的情况下,才能保证性质 5(所有路径包含相同数目的黑结点)
  • 因为插入的结点为红色,因此如果父结点也为红色,则需要调整

调整方法

1). 插入结点为根结点 --> 变色
2). 插入结点的叔结点为红色 --> 父与叔结点变为黑色,祖结点变为红色,并将祖结点作为新插入的结点
3). 插入结点的叔结点为黑色 --> 这里要分 4 种情况, 下面解释 -->(/ \ < >)

  • 调整方法有变色和旋转
调整方法 3) 详细说明
  • 此处方法参考网上的一个方法,将分为 4 种情况,4 种情况分别用 (/ \ < >) 四个符号表示,最终目的是变成 ⋀
  1. 当插入结点、父结点、祖结点在一条线上的时候,如图即可用符号 / 和 \ 表示 :
    在这里插入图片描述
  • 此处用上面左图来说明调整方法,右图变换同理
    在这里插入图片描述
    –> 那么对于 / ,把祖节点扳下来,怎么扳?你用右手向下扳最方便,让 / 变成 ⋀,即右旋
    –> 然后将父结点变为黑色,祖结点变为红色,父节点做为当前结点
  1. 当插入结点、父结点、祖结点不在一条线上时,如图即可用符号 < 和 > 表示:
    在这里插入图片描述
  • 此处用上面右图来说明调整方法,左图变换同理
    在这里插入图片描述

–> 那么对于 >,首先把父结点右旋 ( 将nil算进去就是一个 / ),让 < 变成
–> 然后 \ 按上面1的方法左旋,即可变成 ⋀
–> 最后按上面1的方法完成变色即可

左/右旋补充说明

在这里插入图片描述

3 删除

  • 删除的主要思想:寻找继子,把继子的值赋值给待删除的结点,最后删除继子

以下以xyz来表示结点:
x —> 待删除的结点
y —> 继子结点(实际删除的是这个结点)
z —> 轴心结点(继子的子结点,后续调整以它开始计算黑高)

如何找继子y

  1. 当x的子树不满(没有子树或只有一边子树),y为x本身
  2. 当x拥有左右子树,y为x右子树的最左(最小)结点 ------> y可理解为中序遍历时x的下一个结点

当删除的y为黑色时需要调整 因为影响了黑高
调整思想:(以下所说的子树包含z的父结点)

  • 因为黑高 -1,因此就要通过调整来达到黑高平衡 —> z子树+1 或 z结点的兄弟子树-1(递归上去)
  • 1. 想办法将z子树+1
    因为z子树-1,首先要想办在z子树上找一个红色结点变为黑色;
    如果z子树没有红色结点,就去z子树的兄弟子树上找红色结点,如果有就通过旋转将它调整到z子树上,然后变色;
  • 2. z子树没有办法+1,就想办法将兄弟子树-1(z的父结点下的这棵子树就-1
    如果兄弟子树也没有红色,那么就可以通过兄弟变为红色,使z和兄弟子树都-1(这样父结点下的这棵子树就-1了),然后父结点就可作为新的x去调整
  • 调整时先变色,后旋转
    在这里插入图片描述

调整方法总结
N轴心结点,S兄弟结点,P父结点
说明:N子树黑高为-1,S子树黑高为0

  1. 兄红
    S和P交换颜色(N子树-1,S子树0) --> 以P进行旋转(N子树-1,S子树0) --> N子树有红色结点(原P)可变黑色(N子树0,S子树0)
  2. 兄黑
    2.1 兄子树全黑
    2.1.1 P为红:P与S交换颜色(N子树0,S子树0)
    2.1.2P为黑:S结点变为红色(N子树-1,S子树-1,P子树-1) --> 因为P子树-1,所以将P作为N进行平衡处理
    2.2 兄子树不全黑
    2.2.1 红兄子与兄S在同一侧:该侧红兄子变黑(N子树-1,S子树+1) --> 以P进行旋转(N子树0,S子树0)
    2.2.2 红兄子与兄S不在同一侧:S和该红兄子交换颜色 --> P-S(红)-S子红(黑)形成 > 或 <,因此以S往同侧进行旋转,变为 \ 或 / (N子树-1,S子树0,但将S与红兄子变在同一侧)–> 按2.2.1进行调整

全部代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum _node_color{
	RED = 1,
	BLACK
} EN_NODE_COLOR;

typedef int KEY_TYPE;

typedef struct _rbtree_node {
	unsigned char color;
	KEY_TYPE key;
	void *value;

	struct _rbtree_node *left;
	struct _rbtree_node *right;
	struct _rbtree_node *parent;
} ST_RBTREE_NODE;

typedef struct _rbtree {
	ST_RBTREE_NODE *root;
	ST_RBTREE_NODE *nil;
} ST_RBTREE;

ST_RBTREE_NODE *rbtree_mini(ST_RBTREE *T, ST_RBTREE_NODE *x)
{
	while (x->left != T->nil)
	{
		x = x->left;
	}

	return x;
}

ST_RBTREE_NODE *rbtree_successor(ST_RBTREE *T, ST_RBTREE_NODE *x)
{
	return rbtree_mini(T, x->right);
}

void rbtree_left_rotate(ST_RBTREE *T, ST_RBTREE_NODE *x)
{
	ST_RBTREE_NODE *y = x->right;

	x->right = y->left;
	if (y->left != T->nil)
	{
		y->left->parent = x;
	}

	if (x->parent == T->nil)
	{
		T->root = y;
	}
	else if (x == x->parent->left)
	{
		x->parent->left = y;
		y->parent = x->parent;
	}
	else
	{
		x->parent->right = y;
		y->parent = x->parent;
	}

	x->parent = y;
	y->left = x;
}

void rbtree_right_rotate(ST_RBTREE *T, ST_RBTREE_NODE *x)
{
	ST_RBTREE_NODE *y = x->left;

	x->left = y->right;
	if (y->right != T->nil)
	{
		y->right->parent = x;
	}

	if (x->parent == T->nil)
	{
		T->root = y;
	}
	else if (x == x->parent->right)
	{
		x->parent->right = y;
		y->parent = x->parent;
	}
	else
	{
		x->parent->left = y;
		y->parent = x->parent;
	}

	x->parent = y;
	y->right = x;
}

void rbtree_insert_fixup(ST_RBTREE *T, ST_RBTREE_NODE *x)
{
	while (x->parent->color == RED)
	{
		if (x->parent == x->parent->parent->left)
		{
			ST_RBTREE_NODE *y = x->parent->parent->right;

			if (y->color == RED)		// 叔结点为红色
			{
				x->parent->color = BLACK;
				y->color = BLACK;
				x->parent->parent->color = RED;

				x = x->parent->parent;
			}
			else
			{
				if (x == x->parent->right)					// 为 < 形式
				{
					x = x->parent;
					rbtree_left_rotate(T, x);
				}

				x->parent->color = BLACK;					// 为 / 形式
				x->parent->parent->color = RED;
				rbtree_right_rotate(T, x->parent->parent);
			}
		}
		else
		{
			ST_RBTREE_NODE *y = x->parent->parent->left;

			if (y->color == RED)		// 叔结点为红色
			{
				x->parent->color = BLACK;
				y->color = BLACK;
				x->parent->parent->color = RED;

				x = x->parent->parent;
			}
			else
			{
				if (x == x->parent->left)					// 为 > 形式
				{
					x = x->parent;
					rbtree_right_rotate(T, x);
				}

				x->parent->color = BLACK;					// 为 \ 形式
				x->parent->parent->color = RED;
				rbtree_left_rotate(T, x->parent->parent);
			}
		}
	}

	T->root->color = BLACK;
}

void rbtree_insert(ST_RBTREE *T, ST_RBTREE_NODE *x)
{
	ST_RBTREE_NODE *y = T->root;
	ST_RBTREE_NODE *z = T->nil;

	while (y != T->nil)
	{
		z = y;
		if (x->key < y->key)
		{
			y = y->left;
		}
		else if (x->key > y->key)
		{
			y = y->right;
		}
		else
		{
			return;
		}
	}

	x->parent = z;
	if (z == T->nil)
	{
		T->root = x;
	}
	if (x->key < z->key)
	{
		z->left = x;
	}
	else
	{
		z->right = x;
	}

	x->left = T->nil;
	x->right = T->nil;
	x->color = RED;

	rbtree_insert_fixup(T, x);
}

void rbtree_delete_fixup(ST_RBTREE *T, ST_RBTREE_NODE *N)
{
	while ((N != T->root) && (N->color == BLACK))
	{
		if (N == N->parent->left)		// 兄在右
		{
			ST_RBTREE_NODE *S = N->parent->right;

			if (S->color == RED)		// 3.2兄红
			{
				S->color = BLACK;
				N->parent->color = RED;
				rbtree_left_rotate(T, N->parent);

				S = N->parent->right;
			}

			if (S->color == BLACK)		// 2.兄黑
			{
				if (S->left->color == BLACK && S->right->color == BLACK)		// 2.1 兄子全黑
				{
					S->color = RED;
					N = N->parent;		// parent如果为红,则相当于与兄交换颜色
				}
				else															// 2.2 兄子不全黑
				{
					if (S->right->color == BLACK)
					{
						S->left->color = BLACK;
						S->color = RED;

						rbtree_right_rotate(T, S);
						S = N->parent->right;
					}


					S->color = N->parent->color;
					S->right->color = BLACK;
					rbtree_left_rotate(T, S->parent);

					N = T->root;
				}
			}
		}
		else
		{
			ST_RBTREE_NODE *S = N->parent->left;

			if (S->color == RED)		// 3.1兄红
			{
				S->color = BLACK;
				N->parent->color = RED;
				rbtree_right_rotate(T, N->parent);

				S = N->parent->left;
			}

			if (S->color == BLACK)		// 2.兄黑
			{
				if (S->right->color == BLACK && S->left->color == BLACK)		// 2.1 兄子全黑
				{
					S->color = RED;
					N = N->parent;		// parent如果为红,则相当于与兄交换颜色
				}
				else															// 2.2 兄子不全黑
				{
					if (S->left->color == BLACK)
					{
						S->right->color = BLACK;
						S->color = RED;

						rbtree_left_rotate(T, S);
						S = N->parent->left;
					}


					S->color = N->parent->color;
					S->left->color = BLACK;
					rbtree_right_rotate(T, S->parent);

					N = T->root;
				}
			}
		}
	}

	N->color = BLACK;
}

ST_RBTREE_NODE *rbtree_delete(ST_RBTREE *T, ST_RBTREE_NODE *x)
{
	ST_RBTREE_NODE *y = T->nil;
	ST_RBTREE_NODE *z = T->nil;

	if (x == T->nil)
	{
		printf("delete node is nil\n");
		return T->nil;
	}

	if ((x->left == T->nil) || (x->right == T->nil))	// 子树不满
	{
		y = x;
	}
	else
	{
		y = rbtree_successor(T, x);
	}

	if (y->left != T->nil)
	{
		z = y->left;
	}
	else if (y->right != T->nil)
	{
		z = y->right;
	}
	z->parent = y->parent;

	if (y->parent == T->nil)
	{
		T->root = z;
	}
	else if (y == y->parent->left)
	{
		y->parent->left = z;
	}
	else
	{
		y->parent->right = z;
	}

	if (y != x)
	{
		x->key = y->key;
		x->value = y->value;
	}

	if (y->color == BLACK)
	{
		rbtree_delete_fixup(T, z);
	}

	return y;
}

ST_RBTREE_NODE *rbtree_search(ST_RBTREE *T, KEY_TYPE key)
{
	ST_RBTREE_NODE *x = T->root;

	while (x != T->nil)
	{
		if (key < x->key)
		{
			x = x->left;
		}
		else if (key > x->key)
		{
			x = x->right;
		}
		else
		{
			return x;
		}
	}

	return T->nil;
}

void rbtree_traversal(ST_RBTREE *T, ST_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);
	}
}

int main(void)
{
	int array[20] = {8, 46, 70, 82, 32, 57, 38, 92, 48, 36, 74, 45, 39, 34, 84, 42, 59, 95, 20, 75};
	int len = sizeof(array) / sizeof(array[0]);
	ST_RBTREE_NODE *node = NULL;
	int i;

	ST_RBTREE *T = (ST_RBTREE *)malloc(sizeof(ST_RBTREE));
	if (T == NULL)
	{
		printf("malloc T failed\n");
		return -1;
	}
	memset(T, 0, sizeof(ST_RBTREE));

	T->nil = (ST_RBTREE_NODE *)malloc(sizeof(ST_RBTREE_NODE));
	if (T->nil == NULL)
	{
		printf("malloc T->nil failed\n");
		free(T);
		return -2;
	}
	memset(T->nil, 0, sizeof(ST_RBTREE));
	T->nil->color = BLACK;
	T->root = T->nil;

	node = T->nil;
	for (i = 0; i < len; i++)
	{
		node = (ST_RBTREE_NODE *)malloc(sizeof(ST_RBTREE_NODE));
		node->key = array[i];
		node->color = RED;
		node->value = NULL;

		rbtree_insert(T, node);
	}

	rbtree_traversal(T, T->root);

	printf("-----------------------------------\n");
	ST_RBTREE_NODE *del_cur = T->nil;
	rbtree_delete(T, rbtree_search(T, 74));
	if (del_cur != T->nil)
	{
		free(del_cur);
		del_cur = NULL;
	}

	rbtree_traversal(T, T->root);

	return 0;
}

总结用到红黑树的地方

参考文章:https://www.cnblogs.com/but999/p/12643956.html

  1. java8 hashmap中链表转红黑树。
  2. epoll在内核中的实现,用红黑树管理事件块(文件描述符)。
  3. Java的TreeMap实现
  4. linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块
  5. nginx中,用红黑树管理timer
  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值