保姆级别带你手撕红黑树BRTree

本文深入介绍了红黑树的概念、性质及其重要推论,详细阐述了插入新结点、删除结点的过程,包括插入后的修复和删除后的调整策略。通过代码实现展示了左旋、右旋、查找、插入、删除等操作,帮助读者理解红黑树的平衡维护机制。

目录

二、从头介绍

三、引出红黑树

四、红黑树性质

五、红黑树的一些推论

六、手撕BRTree

6.1、红黑树结点的结构体

6.2、红黑树结构体

6.3、左旋操作

6.4、右旋操作

6.5、插入新结点操作

6.6、插入新结点后调整

6.7、删除结点

6.7.1、查找某个结点

6.7.2、找以某结点为根的那棵树的最小/大值结点

6.7.3、找某结点的中序遍历的后继结点

6.7.4、如何删除结点

6.8、删除结点后进行调整

6.9 测试

七、总结

本文是自己在学习过程中,记录下的一些总结,以便日后复习,同时分享出来,方便与更多人学习交流,共同进步。(不要看篇幅长就吓住,其实不难,只是我画了很多图,做了很详细的解释)鄙人水平有限,若有误,请不吝赐教😁😁😁。

二、从头介绍

红黑树树是一种二叉树,比较常用的数据结构,如果对二叉树不是很熟悉或者有遗忘的朋友,可以看看我之前做的笔记。

第一篇介绍二叉树的基础知识:数据结构与算法 树_振予的博客-优快云博客

第二篇介绍二叉搜索树和二叉平衡树树:数据结构与算法 查找_振予的博客-优快云博客

三、引出红黑树

每当我们打开电脑查找一个文档、在教务系统输入我们的用户名、上网购物搜索时,都会用到查找这个功能,查找的效率直接关系到用户体验的舒适度。不同的应用场景和不同量级别的数据采取的查找策略也不同。下面,从简单的说起:(假如我们的数据量为n)

哈希/散列查找,根据key值计算value,理想情况下效率为O(1)。不过得构造一个好的哈希函数。

线性查找,挨个比对,效率最低,时间复杂度为O(n)。

二分查找,每次能排除一半的数据,前提是有序,时间复杂度为O(logn)。

二叉查找树,平均效率和二分查找一样,但是,当二叉查找树结构成为二叉链(即,全是右孩子或左孩子),又退化成线性查找O(n)。

AVL平衡树,查找效率高,时间复杂度O(logn)。

红黑树,也是一种比较平衡的二叉树,查找时间复杂度O(logn)。

前面总结了查找效率,同时,插入一个数据也需要不能太慢。对于对于线性查找,在线性表中插入一个数据,最坏情况下需要移动所有数据,二分查找也一样。二叉查找树插入效率最好情况为O(logn),最坏会退化到O(n)。因此出现了AVL平衡树,它的所有结点的左右子树高度差不超过1,因此对于查找来说,是极好的,但是当有频繁插入数据操作时,可能每一次插入都需要进行调整,效率就又低下来了,于是有红黑树就好办了,红黑树的平衡要求没有AVL严格,但是又保证了查找的效率,综合两种因素,因此应用场景也比较多(Linux进程调度CFS、Nginx Timer事件管理、Epoll事件块的管理)。

四、红黑树性质

1、每个结点是红色的或者黑色

2、根结点是黑色

3、规定每个叶子结点NIL是黑色

4、每个红色结点的子结点都是黑色

5、对于每个结点,该结点到其所有子孙结点的所有路径上包含相同数目的黑结点(相同黑高)

******(提炼出三条非常非常重要的结论:根为黑、红子为黑、黑高相同)******

(后面堆红黑树进行插入,是否需要修复就是根据这三个性质)

一颗红黑树(隐藏了叶子结点NIL) 

五、红黑树的一些推论

我们可以由前面的几条性质得到一些推论如下:

1、红黑树可以没有红色结点

2、树中一定有黑色存在,即使root==NIL,也可看做黑色

3、红色结点的父结点一定存在且为黑色

4、黑色结点可以连续存在

5、最长路径至多是最短路径的两倍

6、任意一条路径上不可能存在两个连续的红色结点(红色结点没有红色父亲和红色孩子) 

六、手撕BRTree

红黑树能便于我们快速的查找元素,我们在插入一个元素之后或者删除一个元素之后,需要保持红黑树的性质,因此插入后者删除后可能失衡,就得进行调整,红黑树的难点也在这里,下面一一分析。

6.1、红黑树结点的结构体

一个结点有颜色、左孩子、右孩子、父结点、值域和其他操作。如下:

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

#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;

int main()
{
    return 0;
}

6.2、红黑树结构体

typedef struct struct_rbtree{
	rbtree_node *root; // 根结点
	rbtree_node *nil;  // 通用叶子结点的孩子,哨兵
}rbtree;

这里解释一下哨兵:为了便于处理红黑树代码中的边界条件,使用一个哨兵来代表NIL。对于一颗红黑树T,哨兵T.nil是一个与普通结点具有相同属性的对象,它的color为BLACK,其他属性可以设为任意值,如下图,所有指向NIL的指针可以用哨兵T.nil的指针替换。

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值