第十章 红黑树(Red Black Tree)
一开始学红黑树必然一脸懵逼,学完再看还是一脸懵逼
红黑树介绍
红黑树也是一种自平衡的二叉搜索树
- 以前也叫做平衡二叉B树(Symmetric Binary B-tree)
红黑树必须满足以下 5 条性质:
请问下面这棵是红黑树么? (不是一棵红黑树)
红黑树的等价变换
- 有如下一棵红黑树:
- 上面那棵红黑树变成了下面这个样子:
- 下面是一个与上面的红黑树等价的4阶B树
- 红黑树和4阶B树(2-3-4树)具有等价性
- BLACK 节点与它的 RED 子节点融合在一起,形成1个B树节点
- 红黑树的 BLACK节点个数与4阶B树的节点总个数相等
- 网上有些教程:用 2-3树 与 红黑树 进行类比,这是极其不严谨的, 2-3树 并不能完美匹配 红黑树 的所有情况
- 注意:因为界面空间有限,后面展示的红黑树都会省略NULL节点
红黑树 vs 2-3-4树
- 思考:如果上图最底层的BLACK节点是不存在的,在 B树 中是什么样的情形?
- 整棵 B树 只有一个节点,而且是超级节点
几个英文单词
- parent:父节点
- sibling:兄弟节点
- uncle:叔父节点(parent的兄弟节点)
- grand:祖父节点(parent的父节点)
红黑树基础代码
package cn.xx.java.tree;
import java.util.Comparator;
/**
* @author xiexu
* @create 2021-08-09 9:24 上午
*/
public class RBTree<E> extends BST<E> {
private static final boolean RED = false;
private static final boolean BLACK = true;
public RBTree() {
this(null);
}
public RBTree(Comparator<E> comparator) {
super(comparator);
}
/**
* 给节点染色
*
* @param node
* @param color
* @return
*/
private Node<E> color(Node<E> node, boolean color) {
if (node == null) {
return node;
}
((RBNode<E>) node).color = color;
return node;
}
/**
* 把节点染成红色
*
* @param node
* @return
*/
private Node<E> red(Node<E> node) {
return color(node, RED);
}
/**
* 把节点染成黑色
*
* @param node
* @return
*/
private Node<E> black(Node<E> node) {
return color(node, BLACK);
}
/**
* 判断当前节点是什么颜色的
* 空节点默认是黑色
*
* @param node
* @return
*/
private boolean colorOf(Node<E> node) {
return node == null ? BLACK : ((RBNode<E>) node).color;
}
/**
* 当前节点是否为黑色
*
* @param node
* @return
*/
private boolean isBlack(Node<E> node) {
return colorOf(node) == BLACK;
}
/**
* 当前节点是否为红色
*
* @param node
* @return
*/
private boolean isRed(Node<E> node) {
return colorOf(node) == RED;
}
/**
* 红黑树节点
*
* @param <E>
*/
private static class RBNode<E> extends Node<E> {
boolean color;
public RBNode(E element, Node<E> parent) {
super(element, parent);
}
}
}
添加
- B树中,新元素必定是添加到叶子节点中
- 4阶B树所有节点的元素个数 x 都符合 1 <= x <= 3
- 建议新添加的节点默认为 RED,这样能够让红黑树的性质尽快满足(性质 1、2、3、5 都满足,性质 4 不一定)
- 如果添加的是根节点,染成BLACK即可
添加的所有情况
- 添加的情况总共有12种,如下图
- 有4种情况满足红黑树的性质 4:parent 为BLACK
- 同样也满足 4阶B树 的性质
- 因此不用做任何额外处理
- 有 8 种情况不满足红黑树的性质 4:parent 为RED(Double Red)
- 其中前 4 种属于B树节点上溢的情况
添加 - 修复性质4 - LL \ RR
- 判定条件:uncle 不是RED
- parent 染成BLACK,grand 染成RED
- grand 进行单旋操作
- LL:右旋转
- RR:左旋转
- 修复后就是下面这样子
添加 - 修复性质4 - LR \ RL
- 判定条件:uncle 不是RED
- 自己染成BLACK,grand 染成RED
- 进行双旋操作
- LR:parent 左旋转,grand 右旋转
- RL:parent 右旋转,grand 左旋转
- 修复后就是下面这样子
添加 - 修复性质4 - 上溢 - LL
- 判定条件:uncle 是RED
- parent、uncle 染成BLACK
- Grand 向上合并
- 染成RED,当做是新添加的节点进行处理
- grand 向上合并时,可能继续发生上溢
- 若上溢持续到根节点,只需将根节点染成BLACK
添加 - 修复性质4 - 上溢 - RR
- 判定条件:uncle 是RED
- parent、uncle 染成BLACK
- grand 向上合并
- 染成RED,当做是新添加的节点进行处理
- grand 向上合并时,可能继续发生上溢
- 若上溢持续到根节点,只需将根节点染成BLACK
添加 - 修复性质4 - 上溢 - LR
- 判定条件:uncle 是RED
- parent、uncle 染成BLACK
- grand 向上合并
- 染成RED,当做是新添加的节点进行处理
- grand 向上合并时,可能继续发生上溢
- 若上溢持续到根节点,只需将根节点染成BLACK
添加 - 修复性质4 - 上溢 - RL
- 判定条件:uncle 是RED
- parent、uncle 染成BLACK
- grand 向上合并
- 染成RED,当做是新添加的节点进行处理
- grand 向上合并时,可能继续发生上溢
- 若上溢持续到根节点,只需将根节点染成BLACK
添加节点 - 代码实现
/**
* 添加节点之后的操作
*
* @param node 新添加的节点
*/
@Override
protected void afterAdd(Node<E> node) {
Node<E> parent = node.parent;
//添加的是根节点
if (parent == null) {
black(node); //直接将根节点染成黑色
return;
}
//如果父节点是黑色,则直接返回
if (isBlack(parent)) {
return;
}
//uncle节点
Node<E> uncle = parent.sibling();
//grand节点
Node<E> grand = parent.parent;
//uncle节点是红色
if (isRed(uncle)) {
black(parent);
black(uncle);
red(grand);
//祖父节点当做是新添加的节点
afterAdd(grand);
return;
}
//uncle节点不是红色
if (parent.isLeftChild()) { //L
if (node.isLeftChild()) { //LL
black(parent);
red(grand);
rotateRight(grand); //右旋
} else { //LR
black(node);
red(grand);
rotateLeft(parent); //左旋
rotateRight(grand); //右旋
}
} else { //R
if (node.isLeftChild()) { //RL
black(node);
red(grand);
rotateRight(parent); //右旋
rotateLeft(grand); //左旋
} else { //RR
black(parent);
red(grand);
rotateLeft(grand); //左旋
}
}
}
删除
- B树中,最后真正被删除的元素都在叶子节点中
删除 - RED节点
- 直接删除,不用作任何调整
删除 - BLACK节点
有3种情况
- 拥有2个RED子节点的BLACK节点
- 不可能被直接删除,因为会找它的子节点替代删除
- 因此不用考虑这种情况
- 拥有1个RED子节点的BLACK节点
- BLACK 叶子节点
删除 - 拥有1个RED子节点的BLACK节点
- 判定条件:用以替代的子节点是RED
- 将替代的子节点染成 BLACK 即可保持红黑树性质
删除 - BLACK 叶子节点 - sibling为 BLACK
- BLACK 叶子节点被删除后,会导致B树节点下溢(比如删除88)
- 如果 sibling 至少有1个RED子节点
- 进行旋转操作
- 旋转之后的中心节点继承 parent 的颜色
- 旋转之后的左右节点染为BLACK
示例一:
- 以删除 88 节点为例
- 下图所示是LR情况
- 先对 76 进行左旋,再对 80 进行右旋
- 88 的 parent 节点是80,80的颜色是RED
- 所以 78 的颜色染为 80 的颜色RED
- 左右节点 76 和 80 染为BLACK
示例二:
- 以删除 88 节点为例
- 下图所示是RL情况
- 先对 76 进行右旋,再对 80 进行左旋
- 88 的 parent 节点是80,80的颜色是RED
- 所以 76 的颜色染为 80 的颜色RED
- 左右节点 72 和 80 染为BLACK
示例三:
- 以删除 88 节点为例
- 下图所示是 LL / LR,这里以 LL 来说明
- 对 80 进行右旋转
- 88 的 parent 节点是80,80的颜色是RED
- 所以 76 的颜色染为 80 的颜色RED
- 左右节点 72 和 80 染为BLACK
示例四:
- 以删除 88 节点为例
- 下图所示是 LL / LR,这里以 LR 来说明
- 对 76 进行左旋转,对 80 进行右旋转
- 88 的 parent 节点是80,80的颜色是RED
- 所以 78 的颜色染为 80 的颜色RED
- 左右节点 76 和 80 染为BLACK
删除 - BLACK叶子节点 - sibling为BLACK
- 判定条件:sibling 没有1个RED子节点
- 将 sibling 染成RED、parent 染成BLACK即可修复红黑树性质
- 如果 parent 是 BLACK
- 会导致 parent 也下溢
- 这时只需要把 parent 当做被删除的节点处理即可
删除 - BLACK叶子节点 - sibling为RED
- 如果 sibling 是RED
- Sibling 染成BLACK,parent 染成RED,进行旋转
- 于是又回到 sibling 是 BLACK 的情况
删除节点源代码
/**
* 删除节点之后的操作
*
* @param node 被删除的节点 或者 用以取代被删除节点的子节点(当被删除节点的度为1)
*/
@Override
protected void afterRemove(Node<E> node) {
//如果删除的节点是红色 或者 用以取代删除节点的子节点是红色
if (isRed(node)) {
black(node);
return;
}
//parent节点
Node<E> parent = node.parent;
//删除的是根节点
if (parent == null) {
return;
}
//删除的是黑色叶子节点[下溢]
//判断被删除的node是左还是右,因为被删除后该父节点的一边就会为空,所以兄弟节点就在另一边
boolean left = parent.left == null || node.isLeftChild();
Node<E> sibling = left ? parent.right : parent.left;
if (left) { //被删除的节点在左边,兄弟节点在右边
if (isRed(sibling)) { //兄弟节点是红色
black(sibling); //兄弟节点染成黑色
red(parent); //parent节点染成红色
rotateLeft(parent); //右旋
//更换兄弟
sibling = parent.right;
}
//兄弟节点必然是黑色
//如果左右节点为null,null也是黑色
if (isBlack(sibling.left) && isBlack(sibling.right)) {
//兄弟节点没有一个红色子节点,父节点要向下跟兄弟节点合并
boolean parentBlack = isBlack(parent); //处理之前先检查下父节点是不是黑色
black(parent);
red(sibling);
if (parentBlack) {
//只需把 parent 当做被删除的节点处理即可
afterRemove(parent);
}
} else { //兄弟节点至少有1个红色子节点,向兄弟节点借元素
//兄弟节点的右边是黑色,要对兄弟节点进行左旋转
if (isBlack(sibling.right)) {
rotateRight(sibling);
sibling = parent.right; //兄弟节点要重新赋值
}
//sibling继承parent的颜色
color(sibling, colorOf(parent));
black(sibling.right);
black(parent);
rotateLeft(parent);
}
} else { //被删除的节点在右边,兄弟节点在左边
if (isRed(sibling)) { //兄弟节点是红色
black(sibling); //兄弟节点染成黑色
red(parent); //parent节点染成红色
rotateRight(parent); //右旋
//更换兄弟
sibling = parent.left;
}
//兄弟节点必然是黑色
//如果左右节点为null,null也是黑色
if (isBlack(sibling.left) && isBlack(sibling.right)) {
//兄弟节点没有一个红色子节点,父节点要向下跟兄弟节点合并
boolean parentBlack = isBlack(parent); //处理之前先检查下父节点是不是黑色
black(parent);
red(sibling);
if (parentBlack) {
//只需把 parent 当做被删除的节点处理即可
afterRemove(parent);
}
} else { //兄弟节点至少有1个红色子节点,向兄弟节点借元素
//兄弟节点的左边是黑色,要对兄弟节点进行左旋转
if (isBlack(sibling.left)) {
rotateLeft(sibling);
sibling = parent.left; //兄弟节点要重新赋值
}
//sibling继承parent的颜色
color(sibling, colorOf(parent));
black(sibling.left);
black(parent);
rotateRight(parent);
}
}
}
红黑树的平衡
- 最初遗留的困惑:为何那5条性质,就能保证红黑树是平衡的?
- 那5条性质,可以保证 红黑树 等价于 4阶B树
- 相比AVL树,红黑树的平衡标准比较宽松:没有一条路径会大于其他路径的2倍
- 是一种弱平衡、黑高度平衡
- 红黑树的最大高度是 2 * log2( n + 1 ),依然是 O( logn )级别
平均时间复杂度
- 搜索:O( logn )
- 添加:O( logn ),O( 1 )次的旋转操作
- 删除:O( logn ),O( 1 )次的旋转操作
AVL树 VS 红黑树
红黑树完整源代码
BinaryTree类
package cn.xx.java.tree;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
/**
* 二叉搜索树
*
* @author xiexu
* @create 2021-07-26 12:13 下午
*/
public class BST<E> extends BinaryTree<E> {
private Comparator<E> comparator;
public BST() {
this(null);
}
public BST(Comparator<E> comparator) {
this.comparator = comparator;
}
private void elementNotNullCheck(E element) {
if (element == null) {
throw new IllegalArgumentException("element must not be null");
}
}
/**
* 添加元素
*
* @param element
*/
public void add(E element) {
//判空
elementNotNullCheck(element);
//根节点为空,相当于添加第一个节点
if (root == null) {
root = createNode(element, null);
size++;
//新添加节点之后的处理
afterAdd(root);
return;
}
//添加的不是第一个节点
//找到父节点
Node<E> parent = root;
Node<E> node = root;
int cmp = 0;
while (node != null) {
cmp = commpare(element, node.element);
parent = node;
if (cmp > 0) {
node = node.right;
} else if (cmp < 0) {
node = node.left;
} else { //相等直接返回
node.element = element;
return;
}
}
//找到父节点,看看插入到父节点的哪个位置
Node<E> newNode = createNode(element, parent); //创建新节点
if (cmp > 0) {
parent.right = newNode;
} else {
parent.left = newNode;
}
size++;
//新添加节点之后的处理
afterAdd(newNode);
}
/**
* 添加node之后的调整
*
* @param node 新添加的节点
*/
protected void afterAdd(Node<E> node) {
}
/**
* 删除node之后的调整
*
* @param node 被删除的节点 或者 用以取代被删除节点的子节点(当被删除节点的度为1)
*/
protected void afterRemove(Node<E> node) {
}
public void remove(E element) {
remove(node(element));
}
private void remove(Node<E> node) {
if (node == null) {
return;
}
size--;
if (node.hasTwoChildren()) { //度为2的节点
//找到后继节点
Node<E> s = successor(node);
//用后继节点的值,覆盖度为2的节点的值
node.element = s.element;
//删除后继节点
node = s;
}
//删除node节点(node的度必然是1或者0)
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null) { //node是度为1的节点
//更改parent
replacement.parent = node.parent;
//更改parent的left,right的指向
if (node.parent == null) { //node是度为1的节点并且是根节点
root = replacement;
} else {
if (node == node.parent.left) {
node.parent.left = replacement;
} else { //node == node.parent.right
node.parent.right = replacement;
}
}
//删除节点之后的处理
afterRemove(replacement);
} else if (node.parent == null) { //node是叶子节点并且是根节点
root = null;
//删除节点之后的处理
afterRemove(node);
} else { //node是叶子节点,但不是根节点
if (node == node.parent.left) {
node.parent.left = null;
} else { //node == node.parent.right
node.parent.right = null;
}
//删除节点之后的处理
afterRemove(node);
}
}
private Node<E> node(E element) {
Node<E> node = root;
while (node != null) {
int cmp = commpare(element, node.element);
if (cmp == 0) {
return node;
} else if (cmp > 0) {
node = node.right;
} else { //cmp < 0
node = node.left;
}
}
return null;
}
/**
* 判断元素是否存在
*
* @param element
* @return
*/
public boolean contains(E element) {
return node(element) != null;
}
/**
* @param e1
* @param e2
* @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于0,代表e1小于e2
*/
private int commpare(E e1, E e2) {
if (comparator != null) {
return comparator.compare(e1, e2);
} else {
return ((Comparable<E>) e1).compareTo(e2);
}
}
/**
* 前序遍历
*/
public void preorderTraversal() {
preorderTraversal(root);
}
private void preorderTraversal(Node<E> node) {
if (node == null) {
return;
}
//先访问根节点
System.out.println(node.element);
//访问左子节点
preorderTraversal(node.left);
//访问右子节点
preorderTraversal(node.right);
}
/**
* 中序遍历
*/
public void inorderTraversal() {
inorderTraversal(root);
}
private void inorderTraversal(Node<E> node) {
if (node == null) {
return;
}
//先中序遍历左子树
inorderTraversal(node.left);
//输出根节点
System.out.println(node.element);
//再中序遍历右子树
inorderTraversal(node.right);
}
/**
* 后序遍历
*/
public void postorderTraversal() {
postorderTraversal(root);
}
private void postorderTraversal(Node<E> node) {
if (node == null) {
return;
}
//先遍历左子树
postorderTraversal(node.left);
//再遍历右子树
postorderTraversal(node.right);
//最后访问根节点
System.out.println(node.element);
}
/**
* 层序遍历
*/
public void levelOrderTranversal() {
if (root == null) {
return;
}
Queue<Node<E>> queue = new LinkedList<>();
//将头节点入队
queue.offer(root);
while (!queue.isEmpty()) {
//将头结点出队
Node<E> node = queue.poll();
System.out.println(node.element);
//如果左子节点不为空,就将左子节点入队
if (node.left != null) {
queue.offer(node.left);
}
//如果右子节点不为空,就将右子节点入队
if (node.right != null) {
queue.offer(node.right);
}
}
}
}
BST类
package cn.xx.java.tree;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
/**
* 二叉搜索树
*
* @author xiexu
* @create 2021-07-26 12:13 下午
*/
public class BST<E> extends BinaryTree<E> {
private Comparator<E> comparator;
public BST() {
this(null);
}
public BST(Comparator<E> comparator) {
this.comparator = comparator;
}
private void elementNotNullCheck(E element) {
if (element == null) {
throw new IllegalArgumentException("element must not be null");
}
}
/**
* 添加元素
*
* @param element
*/
public void add(E element) {
//判空
elementNotNullCheck(element);
//根节点为空,相当于添加第一个节点
if (root == null) {
root = createNode(element, null);
size++;
//新添加节点之后的处理
afterAdd(root);
return;
}
//添加的不是第一个节点
//找到父节点
Node<E> parent = root;
Node<E> node = root;
int cmp = 0;
while (node != null) {
cmp = commpare(element, node.element);
parent = node;
if (cmp > 0) {
node = node.right;
} else if (cmp < 0) {
node = node.left;
} else { //相等直接返回
node.element = element;
return;
}
}
//找到父节点,看看插入到父节点的哪个位置
Node<E> newNode = createNode(element, parent); //创建新节点
if (cmp > 0) {
parent.right = newNode;
} else {
parent.left = newNode;
}
size++;
//新添加节点之后的处理
afterAdd(newNode);
}
/**
* 添加node之后的调整
*
* @param node 新添加的节点
*/
protected void afterAdd(Node<E> node) {
}
/**
* 删除node之后的调整
*
* @param node 被删除的节点 或者 用以取代被删除节点的子节点(当被删除节点的度为1)
*/
protected void afterRemove(Node<E> node) {
}
public void remove(E element) {
remove(node(element));
}
private void remove(Node<E> node) {
if (node == null) {
return;
}
size--;
if (node.hasTwoChildren()) { //度为2的节点
//找到后继节点
Node<E> s = successor(node);
//用后继节点的值,覆盖度为2的节点的值
node.element = s.element;
//删除后继节点
node = s;
}
//删除node节点(node的度必然是1或者0)
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null) { //node是度为1的节点
//更改parent
replacement.parent = node.parent;
//更改parent的left,right的指向
if (node.parent == null) { //node是度为1的节点并且是根节点
root = replacement;
} else {
if (node == node.parent.left) {
node.parent.left = replacement;
} else { //node == node.parent.right
node.parent.right = replacement;
}
}
//删除节点之后的处理
afterRemove(replacement);
} else if (node.parent == null) { //node是叶子节点并且是根节点
root = null;
//删除节点之后的处理
afterRemove(node);
} else { //node是叶子节点,但不是根节点
if (node == node.parent.left) {
node.parent.left = null;
} else { //node == node.parent.right
node.parent.right = null;
}
//删除节点之后的处理
afterRemove(node);
}
}
private Node<E> node(E element) {
Node<E> node = root;
while (node != null) {
int cmp = commpare(element, node.element);
if (cmp == 0) {
return node;
} else if (cmp > 0) {
node = node.right;
} else { //cmp < 0
node = node.left;
}
}
return null;
}
/**
* 判断元素是否存在
*
* @param element
* @return
*/
public boolean contains(E element) {
return node(element) != null;
}
/**
* @param e1
* @param e2
* @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于0,代表e1小于e2
*/
private int commpare(E e1, E e2) {
if (comparator != null) {
return comparator.compare(e1, e2);
} else {
return ((Comparable<E>) e1).compareTo(e2);
}
}
/**
* 前序遍历
*/
public void preorderTraversal() {
preorderTraversal(root);
}
private void preorderTraversal(Node<E> node) {
if (node == null) {
return;
}
//先访问根节点
System.out.println(node.element);
//访问左子节点
preorderTraversal(node.left);
//访问右子节点
preorderTraversal(node.right);
}
/**
* 中序遍历
*/
public void inorderTraversal() {
inorderTraversal(root);
}
private void inorderTraversal(Node<E> node) {
if (node == null) {
return;
}
//先中序遍历左子树
inorderTraversal(node.left);
//输出根节点
System.out.println(node.element);
//再中序遍历右子树
inorderTraversal(node.right);
}
/**
* 后序遍历
*/
public void postorderTraversal() {
postorderTraversal(root);
}
private void postorderTraversal(Node<E> node) {
if (node == null) {
return;
}
//先遍历左子树
postorderTraversal(node.left);
//再遍历右子树
postorderTraversal(node.right);
//最后访问根节点
System.out.println(node.element);
}
/**
* 层序遍历
*/
public void levelOrderTranversal() {
if (root == null) {
return;
}
Queue<Node<E>> queue = new LinkedList<>();
//将头节点入队
queue.offer(root);
while (!queue.isEmpty()) {
//将头结点出队
Node<E> node = queue.poll();
System.out.println(node.element);
//如果左子节点不为空,就将左子节点入队
if (node.left != null) {
queue.offer(node.left);
}
//如果右子节点不为空,就将右子节点入队
if (node.right != null) {
queue.offer(node.right);
}
}
}
}
BBST类
package cn.xx.java.tree;
import java.util.Comparator;
/**
* @author xiexu
* @create 2021-08-09 4:27 下午
*/
public class BBST<E> extends BST<E> {
public BBST() {
this(null);
}
public BBST(Comparator<E> comparator) {
super(comparator);
}
/**
* 左旋
*
* @param grand
*/
protected void rotateLeft(Node<E> grand) {
Node<E> parent = grand.right;
Node<E> child = parent.left;
grand.right = child;
parent.left = grand;
afterRotate(grand, parent, child);
}
/**
* 右旋
*
* @param grand
*/
protected void rotateRight(Node<E> grand) {
Node<E> parent = grand.left;
Node<E> child = parent.right;
grand.left = child;
parent.right = grand;
afterRotate(grand, parent, child);
}
/**
* 公共代码:不管是左旋转、右旋转,都要执行
*
* @param grand 失衡节点
* @param parent
* @param child
*/
protected void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) {
//让parent成为子树的根节点
parent.parent = grand.parent;
if (grand.isLeftChild()) {
grand.parent.left = parent;
} else if (grand.isRightChild()) {
grand.parent.right = parent;
} else { //grand是根节点
root = parent;
}
//更新child的parent
if (child != null) {
child.parent = grand;
}
//更新grand的parent
grand.parent = parent;
}
/**
* 统一旋转代码
*
* @param r
* @param a
* @param b
* @param c
* @param d
* @param e
* @param f
* @param g
*/
protected void rotate(
Node<E> r, //子树的根节点
Node<E> a, Node<E> b, Node<E> c,
Node<E> d,
Node<E> e, Node<E> f, Node<E> g) {
//让d成为这棵子树的根节点
d.parent = r.parent;
if (r.isLeftChild()) { // r是父节点的左子节点
r.parent.left = d;
} else if (r.isRightChild()) { // r是父节点的右子节点
r.parent.right = d;
} else { // r是根节点
root = d;
}
// a - b - c
b.left = a;
if (a != null) {
a.parent = b;
}
b.right = c;
if (c != null) {
c.parent = b;
}
// e - f - g
f.left = e;
if (e != null) {
e.parent = f;
}
f.right = g;
if (g != null) {
g.parent = f;
}
// b - d - f
d.left = b;
d.right = f;
b.parent = d;
f.parent = d;
}
}
RBTree类
package cn.xx.java.tree;
import java.util.Comparator;
/**
* @author xiexu
* @create 2021-08-09 9:24 上午
*/
public class RBTree<E> extends BBST<E> {
private static final boolean RED = false;
private static final boolean BLACK = true;
public RBTree() {
this(null);
}
public RBTree(Comparator<E> comparator) {
super(comparator);
}
/**
* 添加节点之后的操作
*
* @param node 新添加的节点
*/
@Override
protected void afterAdd(Node<E> node) {
Node<E> parent = node.parent;
//添加的是根节点或者上溢到达了根节点
if (parent == null) {
black(node); //直接将根节点染成黑色
return;
}
//如果父节点是黑色,则直接返回
if (isBlack(parent)) {
return;
}
//uncle节点
Node<E> uncle = parent.sibling();
//grand节点
Node<E> grand = parent.parent;
//uncle节点是红色[B树节点上溢]
if (isRed(uncle)) {
black(parent);
black(uncle);
red(grand);
//grand节点当做是新添加的节点
afterAdd(grand);
return;
}
//uncle节点不是红色
if (parent.isLeftChild()) { //L
if (node.isLeftChild()) { //LL
black(parent);
red(grand);
rotateRight(grand); //右旋
} else { //LR
black(node);
red(grand);
rotateLeft(parent); //左旋
rotateRight(grand); //右旋
}
} else { //R
if (node.isLeftChild()) { //RL
black(node);
red(grand);
rotateRight(parent); //右旋
rotateLeft(grand); //左旋
} else { //RR
black(parent);
red(grand);
rotateLeft(grand); //左旋
}
}
}
/**
* 给节点染色
*
* @param node
* @param color
* @return
*/
private Node<E> color(Node<E> node, boolean color) {
if (node == null) {
return node;
}
((RBNode<E>) node).color = color;
return node;
}
/**
* 把节点染成红色
*
* @param node
* @return
*/
private Node<E> red(Node<E> node) {
return color(node, RED);
}
/**
* 把节点染成黑色
*
* @param node
* @return
*/
private Node<E> black(Node<E> node) {
return color(node, BLACK);
}
/**
* 判断当前节点是什么颜色的
* 空节点默认是黑色
*
* @param node
* @return
*/
private boolean colorOf(Node<E> node) {
return node == null ? BLACK : ((RBNode<E>) node).color;
}
/**
* 当前节点是否为黑色
*
* @param node
* @return
*/
private boolean isBlack(Node<E> node) {
return colorOf(node) == BLACK;
}
/**
* 当前节点是否为红色
*
* @param node
* @return
*/
private boolean isRed(Node<E> node) {
return colorOf(node) == RED;
}
/**
* 重写父类中的createNode方法
*
* @param element
* @param parent
* @return
*/
@Override
protected Node<E> createNode(E element, Node<E> parent) {
return new RBNode<>(element, parent);
}
/**
* 删除节点之后的操作
*
* @param node 被删除的节点 或者 用以取代被删除节点的子节点(当被删除节点的度为1)
*/
@Override
protected void afterRemove(Node<E> node) {
//如果删除的节点是红色 或者 用以取代删除节点的子节点是红色
if (isRed(node)) {
black(node);
return;
}
//parent节点
Node<E> parent = node.parent;
//删除的是根节点
if (parent == null) {
return;
}
//删除的是黑色叶子节点[下溢]
//判断被删除的node是左还是右,因为被删除后该父节点的一边就会为空,所以兄弟节点就在另一边
boolean left = parent.left == null || node.isLeftChild();
Node<E> sibling = left ? parent.right : parent.left;
if (left) { //被删除的节点在左边,兄弟节点在右边
if (isRed(sibling)) { //兄弟节点是红色
black(sibling); //兄弟节点染成黑色
red(parent); //parent节点染成红色
rotateLeft(parent); //右旋
//更换兄弟
sibling = parent.right;
}
//兄弟节点必然是黑色
//如果左右节点为null,null也是黑色
if (isBlack(sibling.left) && isBlack(sibling.right)) {
//兄弟节点没有一个红色子节点,父节点要向下跟兄弟节点合并
boolean parentBlack = isBlack(parent); //处理之前先检查下父节点是不是黑色
black(parent);
red(sibling);
if (parentBlack) {
//只需把 parent 当做被删除的节点处理即可
afterRemove(parent);
}
} else { //兄弟节点至少有1个红色子节点,向兄弟节点借元素
//兄弟节点的右边是黑色,要对兄弟节点进行左旋转
if (isBlack(sibling.right)) {
rotateRight(sibling);
sibling = parent.right; //兄弟节点要重新赋值
}
//sibling继承parent的颜色
color(sibling, colorOf(parent));
black(sibling.right);
black(parent);
rotateLeft(parent);
}
} else { //被删除的节点在右边,兄弟节点在左边
if (isRed(sibling)) { //兄弟节点是红色
black(sibling); //兄弟节点染成黑色
red(parent); //parent节点染成红色
rotateRight(parent); //右旋
//更换兄弟
sibling = parent.left;
}
//兄弟节点必然是黑色
//如果左右节点为null,null也是黑色
if (isBlack(sibling.left) && isBlack(sibling.right)) {
//兄弟节点没有一个红色子节点,父节点要向下跟兄弟节点合并
boolean parentBlack = isBlack(parent); //处理之前先检查下父节点是不是黑色
black(parent);
red(sibling);
if (parentBlack) {
//只需把 parent 当做被删除的节点处理即可
afterRemove(parent);
}
} else { //兄弟节点至少有1个红色子节点,向兄弟节点借元素
//兄弟节点的左边是黑色,要对兄弟节点进行左旋转
if (isBlack(sibling.left)) {
rotateLeft(sibling);
sibling = parent.left; //兄弟节点要重新赋值
}
//sibling继承parent的颜色
color(sibling, colorOf(parent));
black(sibling.left);
black(parent);
rotateRight(parent);
}
}
}
/**
* 红黑树节点
*
* @param <E>
*/
private static class RBNode<E> extends Node<E> {
//建议新添加的节点默认为 RED,
//这样能够让红黑树的性质尽快满足(性质 1、2、3、5 都满足,性质 4 不一定)
boolean color = RED;
public RBNode(E element, Node<E> parent) {
super(element, parent);
}
@Override
public String toString() {
String str = "";
if (color == RED) {
str = "R_";
}
return str + element.toString();
}
}
}