如果面试被问“红黑树”,可以这样回答

正文
预备知识

平衡二叉搜索树
①二叉搜索树
②平衡

③改进二叉搜索树
AVL 树


每个结点的平衡因子只可能是 -1、0、1(如果绝对值超过 1,则认为是失衡)
每个结点的左右子树高度差不超过 1
搜索、插入、删除的时间复杂度是 O(logn)
B 树

特点如下:
1 个结点可以存储超过 2 个元素,可以拥有超过 2 个子结点
拥有二叉搜索树的一些性质
平衡,每个结点的所有子树高度一致
比较矮
①m 阶 B 树的性质(m ≥ 2)
根结点:1 ≤ x ≤ m - 1
非根结点:┌ m / 2 ┐ - 1 ≤ x ≤ m - 1
根结点:2 ≤ y ≤ m
非根结点:┌ m / 2 ┐ ≤ y ≤ m
②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 的处理

如果父结点为黑色:将兄弟结点变为红色;将父结点作为新的替换结点;重新进行删除结点的场景处理。
如果父结点为红色:替换结点的父结点和替换结点的兄弟结点颜色交换;删除结点和替换结点的值交换后,删除替换结点。
最近热文
• 她是北大“一个人的毕业照”主人公,2010级古生物专业独苗,十年后搞起了AI • 刚刚用鸿蒙跑了个“hello world”!跑通后,我特么开始怀疑人生了.... • 今天终于搞懂了:为什么 Java 的 main 方法必须是 public static void? • 朋友入职中软一个月(外包华为)就离职了! 最近整理了一份大厂算法刷题指南,包括一些刷题技巧,在知乎上已经有上万赞。同时还整理了一份6000页面试笔记。关注下面公众号,在公众号内回复「刷题」,即可免费获取!回复「加群」,可以邀请你加入读者群!
明天见(。・ω・。)ノ♡