第十章 红黑树(Red Black Tree)

第十章 红黑树(Red Black Tree)

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

Untitled

红黑树介绍

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

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

Untitled

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

Untitled

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

Untitled

红黑树的等价变换

  • 有如下一棵红黑树:

Untitled

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

Untitled

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

Untitled

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

红黑树 vs 2-3-4树

Untitled

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

几个英文单词

Untitled

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

Untitled

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

添加的所有情况

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

Untitled

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

Untitled

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

Untitled

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

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

Untitled

  • 修复后就是下面这样子

Untitled

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

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

Untitled

  • 修复后就是下面这样子

Untitled

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

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

Untitled

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

Untitled

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

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

Untitled

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

Untitled

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

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

Untitled

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

Untitled

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

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

Untitled

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

Untitled

添加节点 - 代码实现

/**
 * 添加节点之后的操作
 *
 * @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树中,最后真正被删除的元素都在叶子节点中

Untitled

删除 - RED节点

Untitled

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

Untitled

删除 - BLACK节点

Untitled

有3种情况

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

Untitled

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

Untitled

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

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

Untitled

Untitled

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

Untitled

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

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

Untitled

示例一:

  • 以删除 88 节点为例

Untitled

  • 下图所示是 LR 情况

Untitled

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

Untitled

示例二:

  • 以删除 88 节点为例

Untitled

  • 下图所示是 RL 情况

Untitled

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

Untitled

示例三:

  • 以删除 88 节点为例

Untitled

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

Untitled

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

Untitled

示例四:

  • 以删除 88 节点为例

Untitled

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

Untitled

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

Untitled

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

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

Untitled

Untitled

Untitled

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

Untitled

Untitled

Untitled

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

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

Untitled

Untitled

Untitled

删除节点源代码

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

Untitled

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

平均时间复杂度

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

AVL树 VS 红黑树

Untitled

红黑树完整源代码

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

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿小羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值