红黑树简明概述

红黑树的应用场景

hashmap(Java集合中的TreeSet和TreeMap,C++ STL中的set、map)
cfs(进程调度)
epoll(海量响应管理)
Nginx定时器(事件管理)
。。。

红黑树(red_black_tree)这个数据结构主要应用于存储有序数据,并在其中进行快速查找的场景,具有强查找特性。
实践中,其查找,插入和删除过程都可以保持在O(log n)时间内,这里的n 是树中元素的数目。
红黑树既然如此好用,那我们就值得花点时间来认识一下它。

先来说说二叉树

谈红黑树之前,我们先来熟悉一下二叉树,一方面放平学习曲线,一方面也为了解红黑树铺路!

二叉查找/搜索/排序树

也称BST (binary search/sort tree),满足以下条件的二叉树:

若它的左子树不空,则左子树上所有结点的值均小于它的根节点的值;
若它的右子树上所有结点的值均大于它的根节点的值;
它的左、右子树也分别为二叉排序树。

在一棵二叉查找树上,执行查找、插入、删除等操作的时间复杂度为O(log2n)。因为,一棵由n个结点,随机构造的二叉查找树的高度为log2n,所以顺理成章,一般操作的执行时间为O(log2n)。
但若是一棵具有n个结点的线性链,则此些操作最坏情况运行时间为O(n)。
看图便知(来源:0voice课件):摘自0voice课件

平衡二叉树

也称Balanced Binary Tree,平衡二叉树(Balanced Binary Tree)又称AVL树。AVL 树得名于它的发明者 G. M. Adelson-Velsky 和 Evgenii Landis;该树具有以下特点:

每个节点最多只有两个子节点(二叉)	
每个节点的值比它的左子树所有的节点大,比它的右子树所有节点小(有序)
每个节点左子树的高度与右子树高度之差的绝对值不超过1

平衡二叉树必须是一颗二叉排序树(BST),在BST树的基础上满足左右两个子树的高度差的绝对值不超过 1。

红黑树

R-B Tree,全称是Red-Black Tree,又称为红黑树,它一种平衡二叉树。
红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

每个结点是红的或者黑的
根结点是黑的
每个叶子结点是黑的
如果一个结点是红的,则它的两个儿子都是黑的
对每个结点,从该结点到其子孙结点的所有路径上的包含相同数目的黑结点

对比几个例图我们来认识一下红黑树的数据结构:(来源:0voice课件)
在这里插入图片描述

不是,到达叶子结点的黑色节点数量不一致
是,符合全部条件
不是,有的路径含2个黑色节点,有的路径含有3个
不是,根节点不能为红色

如何实现红黑树

实现思路

谨记一个原则,红黑树在进行插入或者删除前,就一定是一个红黑树。
在进行增删操作前,利用了红黑树本身的特性,操作后,也要保证其特性!
插入节点后,如果会破坏红黑树的特性,需要借助变色,左旋,右旋等操作保持其特性!

变色

插入一个节点时,为了保持路径上黑色节点个数一致,我们总是认为新插入的节点是红色
例如有以下场景,当插入的红色节点的父节点和叔节点为红色,则可能破坏了特性4,此时我们可以通过使该节点的父节点和叔节点变为黑色,并将奶奶节点变为红色。

旋转

旋转分为左旋右旋,左旋和右旋都是为了维护红黑树的特性,如果变色的方法不可用,那么我们需要使用旋转的方法。
红黑树的旋转和平衡二叉树的旋转一样,只不过多了变色的步骤。
在这里插入图片描述

简单示例代码

此处仅只展示简单的左旋右旋实现,希望系统了解红黑树的同志,不要局限于此文章,最好去系统了解一下相关项目内的实现,要脚踏实地,知行合一。

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;
} rbtree;
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
}
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;
}

最后声明:

此贴仅做个人学习记录及分享,若有错误还望指正!
本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接0voice,查看详细的服务:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫大魔宝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值