什么是红黑树?这篇讲解很全面!
预备知识
二叉搜索树
平衡
改进二叉搜索树
◆ AVL 树
可以看到 AVL 树具有以下特点:
每个结点的平衡因子只可能是 -1、0、1(如果绝对值超过 1,则认为是失衡)
每个结点的左右子树高度差不超过 1
搜索、插入、删除的时间复杂度是 O(logn)
特点如下:
1 个结点可以存储超过 2 个元素,可以拥有超过 2 个子结点
拥有二叉搜索树的一些性质
平衡,每个结点的所有子树高度一致
比较矮
B 树 VS 二叉搜索树
我们可以得到结论:
B 树和二叉搜索树,在逻辑上是等价的
多代结点合并,可以获得一个超级结点,且 n 代合并的超级结点,最多拥有 (2^n) 个子结点 (至少是 (2^n) 阶 B 树)
红黑树定义和性质
为了保证平衡,红黑树必须满足以下性质:
每个结点是要么是红色或黑色
根结点必须是黑色
叶结点(外部结点、空结点)是黑色
红色结点不能连续(也就是,红色结点的孩子和父亲都是黑色)
对于每个结点,从该点至 nil(树尾端,Java 中为 null 的结点)的任何路径都包含所相同个数的黑色结点
红黑树与 B 树的等价变换
可以得出结论:
红黑树与 4 阶 B 树(2-3-4树)具有等价性
黑色结点与红色子结点融合在一起,形成 1 个 B 树结点
红黑树的黑色结点个数与 4 阶 B 树的结点总个数相等
红黑树的基本操作
N-node:当前结点
P-parent:父结点
S-sibling:兄弟结点
U-uncle:叔父结点(P 的兄弟结点)
G-grand:祖父结点(P 的父结点)
◆ 左旋
把父结点和叔父结点变为黑色
把祖父结点变为红色
把指针定义到祖父结点
把父结点变为黑色
把祖父结点变为红色
对祖父结点右旋
红黑树搜索
具体步骤如下:
从根结点开始检索,把根结点设置为当前结点。
若当前结点为空,返回 nil。
若当前结点不为空,比较当前结点 key 与搜索 key 的大小。
若当前结点 key 等于搜索 key,那么该 key 就是搜索目标,返回当前结点。
若当前结点 key 大于搜索 key,把当前结点的左子结点设置为当前结点,重复步骤 2。
若当前结点 key 小于搜索 key,把当前结点的右子结点设置为当前结点,重复步骤 2。
红黑树插入
从根结点开始检索。
若根结点为空,那么插入结点设为根结点,结束。
若根结点不为空,那么把根结点设为当前结点。
若当前结点为 nil,返回当前结点的父结点,结束。
若当前结点 key 等于搜索 key,那么该 key 所在结点就是插入结点,更新结点的值,结束。
若当前结点 key 大于搜索 key,把当前结点的左子结点设置为当前结点,重复步骤 4。
若当前结点 key 小于搜索 key,把当前结点的右子结点设置为当前结点,重复步骤 4。
将插入结点设为将要替换结点的颜色
更新当前结点的值为插入结点的值
将父结点和叔父结点变为黑色
将祖父结点变为红色
将祖父结点设置为当前插入结点
将父结点变为黑色
将祖父结点变为红色
将祖父结点右旋
将父结点进行左旋
将父结点设为插入结点,得到场景 4.2.1
进行场景 4.2.1 的处理
将父结点变为黑色
将祖父结点变为红色
对祖父结点进行左旋
将父结点进行右旋
将父结点设置为插入结点,得到场景 4.3.1
进行场景 4.3.1 的处理
红黑树插入
若删除结点无子结点,直接删除即可。
若删除结点只有一个子结点,用子结点替换删除结点。
若删除结点有两个子结点,用**后继结点(大于删除结点的最小结点)**替换删除结点。
为了方面理解,我们先约定一下结点的叫法:
R:替换结点
P:替换结点的父结点
S:替换结点的兄弟结点
SL:兄弟结点的左子结点
SR:兄弟结点的右子结点
灰色:结点颜色可能是红色,也可能是黑色
将兄弟结点变为黑色
将父结点变为红色
对父结点进行左旋,得到场景 2.1.2.3
进行场景 2.1.2.3 的处理
将兄弟结点的颜色变为父结点的颜色
将父结点变为黑色
将兄弟结点的右子结点变为黑色
对父结点进行左旋
将兄弟结点变为红色
将兄弟结点的左子结点变为黑色
对兄弟结点进行右旋,得到场景 2.1.2.1
进行场景 2.1.2.1 的处理
如果父结点为黑色:将兄弟结点变为红色;将父结点作为新的替换结点;重新进行删除结点的场景处理。
如果父结点为红色:替换结点的父结点和替换结点的兄弟结点颜色交换;删除结点和替换结点的值交换后,删除替换结点。
将兄弟结点变为黑色
将父结点变为红色
对父结点进行右旋,得到场景 2.2.2.3
进行场景 2.2.2.3 的处理
将兄弟结点的颜色变为父结点的颜色
将父结点变为黑色
将兄弟结点的左子结点变为黑色
对父结点进行右旋
将兄弟结点变为红色
将兄弟结点的右子结点设为黑色
对兄弟结点进行左旋,得到场景 2.2.2.1
进行场景 2.2.2.1 的处理
如果父结点为黑色:将兄弟结点变为红色;将父结点作为新的替换结点;重新进行删除结点的场景处理。
如果父结点为红色:替换结点的父结点和替换结点的兄弟结点颜色交换;删除结点和替换结点的值交换后,删除替换结点。
OK!到这就是这期分享
如果觉得文章有用,请点在看,分享。
历史分享
★ Git 的一些高级用法,效率必备!★ Github上 10 个超好看可视化面板★ 这款 Github 全能下载工具,很强!★ 5个值得学习和练手的Java企业级开源项目,强烈推荐