第十章 红黑树(Red Black Tree)

一开始学红黑树必然一脸懵逼,学完再看还是一脸懵逼

第十章 红黑树(Red Black Tree)_java

红黑树介绍

红黑树也是一种自平衡的二叉搜索树

  • 以前也叫做平衡二叉B树(Symmetric Binary B-tree)

第十章 红黑树(Red Black Tree)_b树_02

红黑树必须满足以下 5 条性质:

第十章 红黑树(Red Black Tree)_数据结构_03

请问下面这棵是红黑树么? (不是一棵红黑树)

第十章 红黑树(Red Black Tree)_平衡二叉树_04

红黑树的等价变换

  • 有如下一棵红黑树:

第十章 红黑树(Red Black Tree)_java_05

  • 上面那棵红黑树变成了下面这个样子:

第十章 红黑树(Red Black Tree)_java_06

  • 下面是一个与上面的红黑树等价的4阶B树

第十章 红黑树(Red Black Tree)_红黑树_07

  • 红黑树4阶B树(2-3-4树)具有等价性
  • BLACK 节点与它的 RED 子节点融合在一起,形成1个B树节点
  • 红黑树的 BLACK节点个数4阶B树的节点总个数相等
  • 网上有些教程:用 2-3树 与 红黑树 进行类比,这是极其不严谨的, 2-3树 并不能完美匹配 红黑树 的所有情况
  • 注意:因为界面空间有限,后面展示的红黑树都会省略NULL节点

红黑树 vs 2-3-4树

第十章 红黑树(Red Black Tree)_平衡二叉树_08

  • 思考:如果上图最底层的BLACK节点是不存在的,在 B树 中是什么样的情形?
  • 整棵 B树 只有一个节点,而且是超级节点

几个英文单词

第十章 红黑树(Red Black Tree)_数据结构_09

  • 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 不一定)

第十章 红黑树(Red Black Tree)_红黑树_10

  • 如果添加的是根节点,染成BLACK即可

添加的所有情况

  • 添加的情况总共有12种,如下图

第十章 红黑树(Red Black Tree)_红黑树_11

  • 有4种情况满足红黑树的性质 4:parent 为BLACK
  • 同样也满足 4阶B树 的性质
  • 因此不用做任何额外处理

第十章 红黑树(Red Black Tree)_b树_12

  • 有 8 种情况不满足红黑树的性质 4:parent 为RED(Double Red)
  • 其中前 4 种属于B树节点上溢的情况

第十章 红黑树(Red Black Tree)_数据结构_13

添加 - 修复性质4 - LL \ RR

  • 判定条件:uncle 不是RED
  1. parent 染成BLACK,grand 染成RED
  2. grand 进行单旋操作
  • LL:右旋转
  • RR:左旋转

第十章 红黑树(Red Black Tree)_数据结构_14

  • 修复后就是下面这样子

第十章 红黑树(Red Black Tree)_平衡二叉树_15

添加 - 修复性质4 - LR \ RL

  • 判定条件:uncle 不是RED
  1. 自己染成BLACK,grand 染成RED
  2. 进行双旋操作
  • LR:parent 左旋转,grand 右旋转
  • RL:parent 右旋转,grand 左旋转

第十章 红黑树(Red Black Tree)_数据结构_16

  • 修复后就是下面这样子

第十章 红黑树(Red Black Tree)_红黑树_17

添加 - 修复性质4 - 上溢 - LL

  • 判定条件:uncle 是RED
  1. parent、uncle 染成BLACK
  2. Grand 向上合并
  1. 染成RED,当做是新添加的节点进行处理

第十章 红黑树(Red Black Tree)_b树_18

  • grand 向上合并时,可能继续发生上溢
  • 若上溢持续到根节点,只需将根节点染成BLACK

第十章 红黑树(Red Black Tree)_数据结构_19

添加 - 修复性质4 - 上溢 - RR

  • 判定条件:uncle 是RED
  1. parent、uncle 染成BLACK
  2. grand 向上合并
  1. 染成RED,当做是新添加的节点进行处理

第十章 红黑树(Red Black Tree)_红黑树_20

  • grand 向上合并时,可能继续发生上溢
  • 若上溢持续到根节点,只需将根节点染成BLACK

第十章 红黑树(Red Black Tree)_b树_21

添加 - 修复性质4 - 上溢 - LR

  • 判定条件:uncle 是RED
  1. parent、uncle 染成BLACK
  2. grand 向上合并
  1. 染成RED,当做是新添加的节点进行处理

第十章 红黑树(Red Black Tree)_红黑树_22

  • grand 向上合并时,可能继续发生上溢
  • 若上溢持续到根节点,只需将根节点染成BLACK

第十章 红黑树(Red Black Tree)_b树_23

添加 - 修复性质4 - 上溢 - RL

  • 判定条件:uncle 是RED
  1. parent、uncle 染成BLACK
  2. grand 向上合并
  1. 染成RED,当做是新添加的节点进行处理

第十章 红黑树(Red Black Tree)_java_24

  • grand 向上合并时,可能继续发生上溢
  • 若上溢持续到根节点,只需将根节点染成BLACK

第十章 红黑树(Red Black Tree)_红黑树_25

添加节点 - 代码实现

/**
* 添加节点之后的操作
*
* @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 Tree)_数据结构_26

删除 - RED节点

第十章 红黑树(Red Black Tree)_红黑树_27

  • 直接删除,不用作任何调整

第十章 红黑树(Red Black Tree)_b树_28

删除 - BLACK节点

第十章 红黑树(Red Black Tree)_java_29

有3种情况

  • 拥有2个RED子节点的BLACK节点
  • 不可能被直接删除,因为会找它的子节点替代删除
  • 因此不用考虑这种情况

第十章 红黑树(Red Black Tree)_数据结构_30

  • 拥有1个RED子节点的BLACK节点
  • BLACK 叶子节点

第十章 红黑树(Red Black Tree)_平衡二叉树_31

删除 - 拥有1个RED子节点的BLACK节点

  • 判定条件:用以替代的子节点是RED

第十章 红黑树(Red Black Tree)_java_32

第十章 红黑树(Red Black Tree)_java_33

  • 将替代的子节点染成 BLACK 即可保持红黑树性质

第十章 红黑树(Red Black Tree)_平衡二叉树_34

删除 - BLACK 叶子节点 - sibling为 BLACK

  • BLACK 叶子节点被删除后,会导致B树节点下溢(比如删除88)
  • 如果 sibling 至少有1个RED子节点
  • 进行旋转操作
  • 旋转之后的中心节点继承 parent 的颜色
  • 旋转之后的左右节点染为BLACK

第十章 红黑树(Red Black Tree)_红黑树_35

示例一:

  • 以删除 88 节点为例

第十章 红黑树(Red Black Tree)_java_36

  • 下图所示是LR情况

第十章 红黑树(Red Black Tree)_平衡二叉树_37

  • 先对 76 进行左旋,再对 80 进行右旋
  • 88 的 parent 节点是80,80的颜色是RED
  • 所以 78 的颜色染为 80 的颜色RED
  • 左右节点 76 和 80 染为BLACK

第十章 红黑树(Red Black Tree)_b树_38

示例二:

  • 以删除 88 节点为例

第十章 红黑树(Red Black Tree)_数据结构_39

  • 下图所示是RL情况

第十章 红黑树(Red Black Tree)_红黑树_40

  • 先对 76 进行右旋,再对 80 进行左旋
  • 88 的 parent 节点是80,80的颜色是RED
  • 所以 76 的颜色染为 80 的颜色RED
  • 左右节点 72 和 80 染为BLACK

第十章 红黑树(Red Black Tree)_数据结构_41

示例三:

  • 以删除 88 节点为例

第十章 红黑树(Red Black Tree)_平衡二叉树_42

  • 下图所示是 LL / LR,这里以 LL 来说明

第十章 红黑树(Red Black Tree)_红黑树_43

  • 对 80 进行右旋转
  • 88 的 parent 节点是80,80的颜色是RED
  • 所以 76 的颜色染为 80 的颜色RED
  • 左右节点 72 和 80 染为BLACK

第十章 红黑树(Red Black Tree)_java_44

示例四:

  • 以删除 88 节点为例

第十章 红黑树(Red Black Tree)_数据结构_45

  • 下图所示是 LL / LR,这里以 LR 来说明

第十章 红黑树(Red Black Tree)_java_46

  • 对 76 进行左旋转,对 80 进行右旋转
  • 88 的 parent 节点是80,80的颜色是RED
  • 所以 78 的颜色染为 80 的颜色RED
  • 左右节点 76 和 80 染为BLACK

第十章 红黑树(Red Black Tree)_平衡二叉树_47

删除 - BLACK叶子节点 - sibling为BLACK

  • 判定条件:sibling 没有1个RED子节点
  • 将 sibling 染成RED、parent 染成BLACK即可修复红黑树性质

第十章 红黑树(Red Black Tree)_数据结构_48

第十章 红黑树(Red Black Tree)_java_49

第十章 红黑树(Red Black Tree)_平衡二叉树_50

  • 如果 parent 是 BLACK
  • 会导致 parent 也下溢
  • 这时只需要把 parent 当做被删除的节点处理即可

第十章 红黑树(Red Black Tree)_java_51

第十章 红黑树(Red Black Tree)_java_52

第十章 红黑树(Red Black Tree)_红黑树_53

删除 - BLACK叶子节点 - sibling为RED

  • 如果 sibling 是RED
  • Sibling 染成BLACK,parent 染成RED,进行旋转
  • 于是又回到 sibling 是 BLACK 的情况

第十章 红黑树(Red Black Tree)_红黑树_54

第十章 红黑树(Red Black Tree)_数据结构_55

第十章 红黑树(Red Black Tree)_平衡二叉树_56

删除节点源代码

/**
* 删除节点之后的操作
*
* @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树

第十章 红黑树(Red Black Tree)_平衡二叉树_57

  • 相比AVL树,红黑树的平衡标准比较宽松:没有一条路径会大于其他路径的2倍
  • 是一种弱平衡、黑高度平衡
  • 红黑树的最大高度是 2 * log2( n + 1 ),依然是 O( logn )级别

平均时间复杂度

  • 搜索:O( logn )
  • 添加:O( logn ),O( 1 )次的旋转操作
  • 删除:O( logn ),O( 1 )次的旋转操作

AVL树 VS 红黑树

第十章 红黑树(Red Black Tree)_红黑树_58

红黑树完整源代码

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();
}
}

}