红黑树
一、红黑树的原理
红黑树和2-3-4树是等价的,由于绝大多数编程语言直接实现2-3-4树会非常繁琐,所以一般是通过实现红黑树来实现替代2-3-4树,而红黑树本也同样保证在O(lgn)的时间内完成查找、插入和删除操作。
红黑树可以看作是一颗节点带颜色的二叉树搜索树。节点只有两种颜色,即红色和黑色。(红黑色只是逻辑颜色,只为区分节点,不带实际意义)
红黑树有如下的特性:
- 每个节点不是红色的就是黑色的。
- 根节点是黑色的。
- 叶子节点是黑色的。
- 如果一个节点是红色的,则它的两个儿子都是黑色的。
- 对于每个节点,从该节点到其任意叶子节点的路径上的黑色节点数目相同。
上面的性质保证了红黑树的任意路径节点数最大相差不会超过n-1(n为最短路径上的节点数,即该路径上没有红色节点)
对于红黑树的叶子节点,我们一般会设置一个特殊的黑色节点(nil),并将其作为叶子节点或其他空节点。
红黑树的插入和删除节点是发生在叶子节点的父节点上的。
如图,上面是一颗红黑树,对于节点“5”、“7”、“9”、“11”,它们都各自有两个”nil“叶子节点。
二、红黑树的平衡
红黑树的平衡是依靠旋转和颜色替换来实现的。
颜色替换为两个节点交换各自的颜色属性。
旋转则为树的左旋和右旋。
红黑树的节点带有指向父节点的指针,因此在左旋、右旋时,一共需要改变六个指向。
如左旋时,x指向父节点和指向右子节点的指向、y指向父节点和指向左子节点的指向、x的父节点指向x的指向、b指向父节点y的指向共6个指向需要相应变化。
左旋、右旋时需要保证x节点和y节点的存在。(一般设计函数会默认这两个节点存在,因此使用者需要自己判断)
三、红黑树的插入
红黑树在插入节点前,是一颗红黑树。
因此,往红黑树增加一个红色节点,能够最大限度的保证红黑树的性质。
但是,增加节点后,可能会导致该树不符合第4条性质,即红色节点可能插入在红色节点之下,因此在插入后还需要进行树的平衡。
1. 插入操作的实现
第一步,找到合适的插入位置并插入
根据搜索树的性质找到适合插入的位置,并插入节点
第二步,平衡树
因为当前节点的插入可能导致树的不平衡,将当前节点设置为调整节点,调用调整函数
2. 平衡函数原理
平衡函数的一个参数应为插入的当前节点,函数实现如下:
当前节点的父节点是黑色节点,不需要做任何处理
当前节点的父节点是红色节点
当前节点的父节点是祖父节点的左子树
叔父节点(即祖父节点的右子树)是红色的,
将父节点和叔父节点变为黑色节点,将祖父节点变为红色节点,将祖父节点设置为调整节点
叔父节点是黑色的,且父节点是左子节点
当前节点是父节点的右子节点,将父节点设置为调整节点,父节点左旋 (此目的是为了将调整节点、父节点、祖父节点置换到一条直线上)
当前节点是父节点的左子节点,将调整节点的父节点置位黑色,将祖父节点置位红色,将祖父节点右旋,调整完成
当前节点是祖父节点的右子树,(以下操作与上述操作呈镜像)
四、红黑树的删除
红黑树的中序遍历是一个递增序列,我们将在此序列中当前节点的下一相邻节点称为后继节点。
二叉树节点的删除分三种情况
- 删除节点是叶子节点,直接删除
- 删除节点只有一个子节点,将子节点和父节点链接起来,删除节点
- 删除节点有两个子节点,寻找删除节点的后继节点,并用后继节点覆盖删除节点,然后将后继节点作为删除节点
很显然,第三种情况最后也会转换成前两种情况,再进行删除。
1. 删除操作的实现
第一步,找到删除节点
根据二叉树节点的删除我们可以同理找到红黑树的删除节点
第二步,删除节点后平衡树
将节点删除后,树可能变得不平衡,因此我们可能需要平衡树
删除节点是红色的,树不会变得不平衡,不需要做任何处理
删除节点是黑色的,树变得不平衡,需要调用平衡函数
2. 平衡函数原理
节点删除后,不平衡的区块可以压缩为删除节点的子树,因此,平衡函数的一个参数应为删除节点的子节点,下面称为调整节点
调整节点为红色或根节点,将调整节点变为黑色,平衡完成
调整节点不是根节点且为黑色
调整节点是左子节点
调整节点的兄弟节点是红色,将兄弟节点左旋,将兄弟节点设置为黑色,父节点设置为红色,调整节点的兄弟节点发生变化且必定为黑色,进行下述步骤
调整节点的兄弟节点是黑色
兄弟节点的子节点(即侄子节点)全为黑色
将兄弟节点设置为红色,将父节点设置为新的调整节点
兄弟节点的右子节点(远侄子节点)为红色,左子节点(近侄子节点)颜色任意
用父节点的颜色覆盖兄弟节点,父节点设置为黑色,父节点左旋,将远侄子节点设置为黑色,调整完成
远侄子节点为黑色,近侄子节点为红色
交换兄弟节点和近侄子节点的颜色,兄弟节点右旋,调整节点的兄弟节点发生变化,重新判断
调整节点是右子节点,(以下操作与上述操作呈镜像)
五、红黑树的应用
红黑树往往会出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况。在数据较小,可以完全放到内存中时,红黑树的时间复杂度比B树低。
如linux中进程的调度用的是红黑树。定时器的存储数据结构也可以用红黑树实现。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
github:https://github.com/illusorycat/RBtree.git
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现