红黑树的用途和实现

本文探讨了红黑树在map、nginx、CPU调度、内存管理及malloc内存碎片管理中的应用,对比了红黑树与AVL树,并深入讲解了红黑树的性质、节点结构、旋转操作和黑高的概念。还提供了红黑树的C++实现和关键概念解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、红黑树用途在哪里?

1 map–>
2 nginx–>
3 定时器–>
4 cfs (进程调度的集合 )(操作系统中用红黑树存储的集合)(查找速度快,有顺序)
5 内存管理(红黑树的平衡关系);
问题:典型的malloc的内存碎片?
解答:一块内存对应一个key;
key指向的内存的地址 加上长度就是对内存碎片的管理, key value -->查找。
问题:红黑树有什么应用呢?
1>大多数自平衡BST(self-balancing BST) 库函数都是用红黑树实现的,比如C++中的map 和 set (或者 Java 中的 TreeSet 和 TreeMap)。
2>红黑树也用于实现 Linux 操作系统的 CPU 调度。完全公平调度(Completely Fair Scheduler)使用的就是红黑树。

二、概念

1.每个结点是红的或者黑的
2 根结点是黑的
3 每个叶子结点是黑的(NULL)
4 树中不存在两个相邻的红色结点(即红色结点的父结点和孩子结点均不能是红色)
5 从任意一个结点(包括根结点)到其任何后代 NULL 结点(默认是黑色的)的每条路径都具有相同数量的黑色结点。
在这里插入图片描述
这就是一颗典型的红黑树,树中的每个结点的颜色要么是黑色,要么是红色;根结点 6 为黑色结点;树中不存在两个相邻的红色结点,比如结点 15 为红色结点,其父亲节点 6 与两个孩子结点就一定是黑色,而不能是红色;从结点到其后代的 NUll结点 的每条路径上具有相同数目的黑色结点,比如根结点 6 到其左子树的 NULL结点 包含三个黑色结点,到其右子树所有的 NULL 结点也包含三个黑色结点。 可能还不够清晰,为此我对上图做了修改为所有默认为黑色的 NULL 结点给了一个标记。

在这里插入图片描述
现在解释规则的第四条简直不能再清晰了!比如根结点 6 到 NULL结点 a 的路径 6→2→a 上的黑色结点为 3 个,从根结点 6 到结点 c 的路径 6→15→10→9→c 中包含的黑色结点个数也是 3 个,同理从根结点 6 到其他所有 NULL结点 的黑色结点数都是 3 。再举个栗子,从红色结点 15 到NULL结点 d 的路径 15→18→g 包含 2 个黑色结点,到NULL结点 c 的路径 15→10→9→c 也包含黑色结点 2 个,从结点 15 到其所有后代的 NULL结点的 黑色结点数目都是 2 。

###红黑树RBT与平衡二叉树AVL比较:

AVL 树比红黑树更加平衡,但AVL树在插入和删除的时候也会存在大量的旋转操作。所以当你的应用涉及到频繁的插入和删除操作,切记放弃AVL树,选择性能更好的红黑树;当然,如果你的应用中涉及的插入和删除操作并不频繁,而是查找操作相对更频繁,那么就优先选择 AVL 树进行实现。

###什么是一颗红黑树的黑高(Black Height)?

在一颗红黑树中,从某个结点 x 出发(不包含该结点)到达一个叶结点的任意一条简单路径上包含的黑色结点的数目称为 黑高 ,记为 bh(x) 。
譬如结点6对应的黑高 和结点15 对应的黑高 都是2;
6->2->null ;
15->10->9_null(9是红色结点不算入黑高计算种);
在这里插入图片描述

二、实现红黑树

*实现红黑树的一个结点

typedef int KET_TYPE  //key的类型

typedef struct _rbtree_node{
	unsinged char color;
	struct _rbbtree_node *left;
	struct _rbbtree_node *right;
	struct _rbbtree_node *parent; //结点的父亲
	KEY_TYPE key;  //rbtree上的结点的key 对应隐藏的value
	void *value; 
}rbtree_node;

实现红黑树

typedef struct _rbtree{
	rbtree_node *root;
	//根据红黑树的性质----每个叶子结点是黑的
	//做一个通用的叶子结点(*nil),把所有的叶子结点放入其中去判断是否为黑色;
	rbtree_node *nil;
};

红黑树的旋转
在这里插入图片描述
实现红黑树的左旋

void _left_rotate(rbtree *T,rbtree_node *x){
	rtree_node *y =x->right; // 前提条件 y是x的右子结点

	x->right = y->left;  //把x的右子结点指向 y的左子结点b
	if(y->left != T->nil) {//  判断此时y的左子结点是否为空结点
	y->left->parent = x; // b的parent 指向x
	}

	y->parent = x->parent;// 把y的父结点指向x的父结点
	if(x->parent == T->nil){  //判断x的父结点3种情况 1根 2左 3右 情况来x的父结点指向y
		T->root = y
	}else if(x == x->parent->left){
		x-parent->left = y;   //2左
	}else {
	  	x->parent->right = y;  //3右
	}
	
	y->left = x;   // 此时y结点已经在x原来的父结点上 将y的左子 指向x
	x->parent = y;   // x的父结点指向y
}

实现红黑树的右旋

void _right_rotate(rbtree *T,rbtree_node *y){
	rtree_node *x =y->left; // 前提条件 x是y的左子结点

	y-left = x->right;  
	if(x->right != T->nil) {//  判断此时y的左子结点是否为空结点
	x->right->parent = y; // b的parent 指向y
	}

	x->parent = y->parent;// 把x的父结点指向y的父结点
	if(y->parent == T->nil){  //判断y的父结点3种情况 1根 2左 3右 情况来y的父结点指向x
		T->root = x
	}else if(y == y->parent->left){
		y-parent->left = x;   //2左
	}else {
	  	y->parent->right = x;  //3右
	}
	
	x->right= y;   
	y->parent = x;   
}

三、总结

以上就是今天所掌握的内容,本文仅仅简单介绍了红黑树的用途和实现操作,还有插入删除,着色旋转的问题等待学习。

参考 >图解红黑树的实现<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值