红黑树
一、定义
下图为一标准红黑树

满足如下要求的树是红黑树
1.每个节点不是红色就是黑色
2.根节点和叶节点(NIL)都是黑色
注:NIL节点即空节点,实际不存在,是我们为了便于处理边界情况添加的,我们将NIL节点叫叶节点,这样原本红黑树中的叶节点就变成了内节点。NIL与普通节点具有相同属性,颜色为黑
3. 每个红色节点的父节点必为黑色
由此条我们可推导出 ● 红黑树中不存在两个红色节点相连的情况 ● 任意一条长度为N的简单路径最多有N/2个红节点,或者说最少有N/2个黑节点。
4. 每个节点沿任意路径到达叶节点的黑高度相同,
或称任意一个非叶节点沿任意简单路径到叶节点经过的黑色节点数相同(计算黑高度时包含NIL节点,但不包含起始节点,NIL节点黑高度为0)
注:简单路径,即不经过重复节点的路径
二、证明: 红黑树查找数量级为O(log N)
即需证明红黑树高度为log(N)数量级
我们主要是依靠红黑树的3 4号定义保持树的高度
例如一棵完全二叉搜索树,将其染色为全黑,即为一棵红黑树
证:具有N个内部节点的红黑树高度<=2log(N+1)
首先将开头树中每一个 红节点
与他的 黑色父节点
合并。合并完如图
我们将这种树叫做2-3-4树
2-3-4树的性质有两个
- 每个节点有2-4个子节点,有1-3个项.
-
所有叶节点有相同的深度(等于红黑树中黑高度)
注:根据红黑树性质4,根节点沿任意简单路径到达叶节点的黑色节点数相等,而我们将每个红色节点与其黑色父节点合并后,整棵树就只剩下黑色节点,因而所有叶节点具有相同深度并等于黑高度
证明
性质1:任意一棵二叉树的的叶节点数总是等于内部节点数+1(即有N个内部节点的二叉树总有N+1个叶节点)


由2-3-4树的 性质1 可知
性质2:一棵高为h'的2-3-4树有2^h' ~ 4^h'个叶节点
设2-3-4树的高度为h',红黑树的高度为h
设2-3-4树有N个内部节点,则由性质1和性质2可得
2^h' ≤ N+1 ≤ 4^h'
对于其中 2^h' ≤ N+1
两边求对数有 h' ≤ log(N+1)
又因为上图2-3-4树是由红黑树中的红节点和父节点合并而来,因而其高度为红黑树中根节点的黑高度;而在红黑树中从根到叶的任意一条简单路径上最少有N/2个黑节点,所以有 h ≤ 2h'
即h/2 ≤ h'
所以h/2 ≤ h ≤ log(N+1) 因而 h ≤ 2log(N+1)
所以红黑树为O(log N)量级
三、插入 (推荐看清华大学邓俊辉的算法视频)
设有一红黑树T,要插入一个值X
首先将X按照标准二叉树插入方法插入红黑树中
注
1. X.P = X.Parent 即X的父节点
2. 设新插入节点的颜色为红色
当P所指的不是根节点或P所指节点是红色时重复执行下面的操作。
按照插入节点的父节点是爷爷节点的 左孩子 还是 右孩子 ,分为两大类情况,每大类有3小类
叔叔节点指的是爷爷节点的另一个孩子
第一大类 当x的父节点是爷爷节点的左孩子 x.p == leftChild(x.p.p)
1.1 当x的叔叔节点(图中的y)是红色的时候

处理方法
将x的父节点和叔节点设为黑色,然后将x的爷爷节点设为红色,将P指向爷爷节点x.p.p
1.2 当x的父节点是红色,x是父节点的左孩子,叔叔节点是黑色
1.右旋
2.将两个子节点变成黑色,将右旋后的根节点变成红色,重新变为 CASE 1
1.3 当X是X.P的右孩子,且叔叔节点是黑色时

1. 先左旋将 1.3 状态转换为 1.2状态
2. 然后按照 1.2 处理
不难发现旋转完成后的根节点是红色,所以有可能根节点和其父亲发生冲突,需要对根节点继续进行调整,直到冲突完成
注: 可以对α,β,γ和叔叔节点进行检测,若全部为黑色,则可将重构后的根节点染为黑色,将两个字节点染成红色。免去了不必要的向上调整
`小工具 3+4重构`
我们通过观察case2和case3的结果不难发现他们结果的结构是类似的。只是所连接的节点不同,所以我们可以直接对 1.2和 1.3 进行3+4重构,减少不必要的旋转次数
另一大类是反转过来的情形,原理与上三种基本相同,反转过来处理就OK
四、删除
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战