程序员内功心法(二叉树搜索树、AVL树、234树、红黑树汇总)

        历经了一个多月,终于完成了二叉搜索树的学习和整理。以前只是零散的发布出来,并无作一个完整的分享。此次,我将以前的内容整理到一块儿,一次性的对这个话题作个终结。若是看了这篇,仍是不懂二叉搜索树,那你就来后台留言找我,我将给您一一解答。这篇文章主要介绍二叉搜索树、平衡二叉树里的AVL树2-3-4树红黑树。能够点击分篇连接查看更细致的内容javascript

在生活中咱们常常会使用到搜索的功能。在咱们数据量不大的状况下,可使用每次遍历所有数据,查询咱们的目标数据。当数据量增长时,咱们遍历的方式就有些力不从心了;也能够将数据的数据排序,使用比较高效的二分查找方式,可是在插入或删除数据时,数组表现就会很慢。因此咱们能够结合二分查找查询的高效 + 链表添加删除的高效性来实现高效搜索(符号表)的状况java

下面我将列举一些树的内容定义(后续全部的代码使用Java语言实现)node

  • 树由节点构成,每一个节点都有一个父节点(根结点不存在父节点)算法

  • 节点包含的连接能够指向不存在的NULL或者其余真实存在的节点数组

  • 每一个节点均可以包含多个子连接,将子连接的个数称为度;树的度是指全部的子节点中最大的度(将度为2的树称为二叉树、度为3的树称为三叉树等)。如图1~3示markdown

  • 叶节点:没有子节点的节点 如图-1的B、C、D节点数据结构

  • 父节点:有子树的节点是其子树的根节点的父节点 图-1的A节点是B、C、D节点的父节oop

  • 子节点:若A节点是B节点的父节点,那么B是A的子节点,子节点也能够成为孩子节点 图-3的A节点是B、C、D的父节点,同时也是H节点的子节点性能

  • 兄弟节点:具备相同一个父节点的个节点彼此是兄弟节点 图-1的B、C、D学习

二叉搜索树

定义

  • 每一个节点只指向一个父节点,最多包含左右两个子连接

  • 左子边节点的Key小于父节点、右子节点的Key大于父节点 如图-4示

T data;

    TreeNode<T> left;

    TreeNode<T> right;

    int size;
复制代码

查找

 每一个节点只指向一个父节点,最多包含左右两个子连接

  • 左子边节点的Key小于父节点、右子节点的Key大于父节点 如图-4示

T data;

    TreeNode<T> left;

    TreeNode<T> right;

    int size;
复制代码

查找

if (Objects.isNull(node)) {
        return null;
    }
    T val = node.data;
    int res = val.compareTo(element);   //和node节点比较
    if (res == 0) {                     //等于node的值,表示查询到
        return node;
    }
    if (res < 0) {                      //节点的值小于要查询的值,向右递归
        return find(element, node.getRight());
    }
    return find(element, node.getLeft());   //节点的值大于查询的值,向左递归
}
复制代码

查询极值(极大/极小值)

根据查找二叉树的特性,极值存在于叶节点或者只包含一个子节点的父节点中

//查询极小值,一直向左查询,若是没有左节点,则认为当前节点最小 例子:A节点
public TreeNode<T> findMin(TreeNode<T> node){
    if (Objects.isNull(node.getLeft())) {
        return node;
    }
    return findMin(node.getLeft());
}
//查询极大值,一直向右查询,若是没有右节点,则认为当前节点最大 例子:Z节点
public TreeNode<T> findMax(TreeNode<T> node){
    if (Objects.isNull(node.getRight())) {
        return node;
    }
    return findMax(node.getRight());
}
复制代码

插入

图-7展现了插入Z的做为F右子节点的状况(插入到左子节点的状况相似,再也不赘叙)

图-8展现了被插入节点存在的状况。

public void add(T element) {
    if (element == null) {
        throw new RuntimeException("数据不能为NULL");
    }
    TreeNode<T> node = new TreeNode<>();
    node.data = element;
    if (Objects.isNull(root)) {
        root = node;
        return;
    }
    addImpl(root, node);
}
private void addImpl(TreeNode<T> root, TreeNode<T> node) {
    T val = root.data;
    T element = node.data;
    int sub = element.compareTo(val);
    //包含要插入的值,不处理
    if (sub == 0) {
        return;
    }
    //插入的值大于根节点的值,将新节点做为根节点的右子节点
    if (sub > 0) {
        TreeNode<T> right = root.getRight();
        if (Objects.isNull(right)) {
            root.setRight(node);
            return;
        }
        addImpl(right, node);
    } else {        //插入的值小于根节点的值,将新节点做为根节点的左子节点
        TreeNode<T> left = root.getLeft();
        if (Objects.isNull(left)) {
            root.setLeft(node);
            return;
        }
        addImpl(root.getLeft(), node);
    }
}
复制代码

删除

因为删除节点比较复杂,咱们先看下删除极大值(极小值)的状况,为节点删除作好准备工做

删除最小值

因为二叉搜索树的特色二(左子边节点的Key小于父节点、右子节点的Key大于父节点)那么最小值节点要么是叶子节点或者包含右子节点的状况

  • 极小值节点是叶子节点,能够直接移除

  • 极小值节点有一个右子节点,将右子节点替换为父节点(若是还包含左子节点,那么当前节点非最小值)

//移除最小的节点,将返回的值做为根节点
private TreeNode<T> deleteMin(TreeNode<T> node) {
    if (Objects.isNull(node.getLeft())) {   //没有左子节点,返回右子节点
        return node.getRight();
    }
    TreeNode<T> min = deleteMin(node.getLeft());    //递归左子树
    node.setLeft(min);
    return node;
}
复制代码

删除最大值

和删除最小值的状况类似。只不过递归的是右子树

  • 极大值节点是叶子节点,能够直接移除

  • 极大值节点有一个左子节点,将左子节点替换为父节点(若是还包含右子节点,那么当前节点非最大值)

if (Objects.isNull(node.getRight())) {
        return node.getLeft();
    }
    TreeNode<T> max = deleteMax(node.getRight());
    node.setRight(max);
    return node;
}
复制代码

删除节点

咱们将删除节点的状况概括以下

  • 被删除节点是叶子节点,能够直接移除

  • 被删除节点只包含一个子节点(左子节点或者右子节点),咱们须要须要将子节点替换到父节点

  • 被删除节点包含两个子节点,若是直接移除E节点,那么子节点D、F将会丢失。咱们须要转换思路,将包含两个子节点的状况转换为上两种状况。下面咱们介绍下如何处理(T.Hibbard 1962年提出的方法,膜拜巨佬)

  • 咱们使用前驱节点(后续节点)的值替换被删除节点,而后删除前驱节点(后继节点)

  • 前驱节点:当前节点的左子树中的最大值

  • 后继节点:当前节点的右子树中的最小值

//删除element的节点,返回根结点的引用
public TreeNode<T> delete(T element, TreeNode<T> node){
    if (Objects.isNull(node)) {
        return null;
    }
    T val = node.data;
    int res = val.compareTo(element);
    if (res < 0) {          //被删除节点在node的右子树
        TreeNode<T> rNode = delete(element, node.getRight());
        node.setRight(rNode);
    } else if (res > 0) {   //被删除节点在node的左子树
        TreeNode<T> lNode = delete(element, node.getLeft());
        node.setLeft(lNode);
    } else {                //node为被删除节点
        //包含一个子节点,使用子节点替换父节点
        if (Objects.isNull(node.getLeft())) {   
            return node.getRight();
        }
        if (Objects.isNull(node.getRight())) {
            return node.getLeft();
        }
        //左右节点均存在,使用后继节点代替,移除后继节点
        TreeNode<T> tmp = node;
        node = findMin(node.getRight());
        TreeNode<T> rNode = deleteMin(tmp.getRight());
        node.setRight(rNode);
        node.setLeft(tmp.getLeft());
    }
    return node;
}
复制代码

至此,咱们已经完成了二叉搜索树的增长、查询、删除的方法。咱们发现二叉搜索树的实现并不困难,而且在大多数场景下也能正常运行。二叉搜索树在极端状况的性能也是不可忍受的。

后面咱们将讲述一种在任何场景初始化,运行时间都将是对数级的

AVL树

接上面二叉树搜索树了解到二叉搜索树在极端状况也不能知足咱们对于查询性能的要求。

二叉树的一些统计特性

  • 第n层最多的节点个数2n-1

  • 高度为h的二叉树,最多包含2h-1个节点,因此n个节点的二叉树的最小高度是log2n + 1

  • 查找成功时,查找次数不会超过树的高度h

二叉树查询性能的衡量

咱们下面来使用 A - H字符来观察二叉搜索树在不一样的插入顺序下构造的树的结果

天然顺序的平均查找长度为ASL=(1+ 2 + 3 + 4+ 5+ 6+ 7 +8) / 8 = 4.5

计算特定顺序的平均查找长度ASL=(1 + 2*2 + 3*4 + 4*1) / 8 = 2.6

当咱们数据相同,可是采用不一样的插入顺序,使平均查找长度不同。因此咱们要解决这个问题,先观察两个初始化方式两个树的特色,大体发现使用特定顺序初始化的树,感受树的节点分布比较平衡。因为统计特色3和特色2,咱们但愿n个节点的二叉树的接近log2n + 1,那么咱们就能够最大化的提高查询性能.

因此为了解决这个问题,咱们引入新的二叉搜索树实现-平衡二叉树(AVL树)

AVL树内容定义

  • 平衡因子BalanceFactor:左右子树的高度差BF=HL - HR

  • 规定左右子树的高度差的绝对值不超过1 |BF| ≤ 1

节点定义

原有节点的基础上增长height属性

class AVLNode<T extends Comparable<T>> {

    private T data;

    //左节点
    private AVLNode<T> left;

    //右节点
    private AVLNode<T> right;

    //当前节点的高度
    private int height;
}
复制代码

高度计算

因为平衡二叉树的平衡指高度方面的平衡,咱们先来计算树的高度

树的高度H指:左HL右HR子树高度的最大值 + 1

int height(AVLNode<T> node){
    if (Objects.isNull(node)) {
        return 0;
    }
    int rHeight = height(node.getRight());
    int lHeight = height(node.getLeft());
    return Math.max(rHeight, lHeight) + 1;
}
复制代码

查找

因为平衡二叉树也是二叉查找树的一种,查询方式和二叉搜索树相同,再也不赘述。

调整平衡

为了保证左右平衡,因此咱们一系列的操做来维持左右子树的高度在BF规定的范围以内

插入分类

空树时,直接初始化为根结点。

针对做为子节点的插入,插入节点只能为被插入节点的左节点B或者右节点F。而被插入节点D能够是其父节点G的左节点或其父节点A的右节点。因此咱们将全部状况分为4类:GDB路径(LL插入)、GDF路径(LR插入)、ADF路径(RR插入)、ADB路径(RL插入)

接下来咱们将处理全部的状况

RR插入

当插入节点在右子树的右节点上(ADF路径)

操做步骤:

  1. 将右子节点D做为根节点

  2. 原根节点A做为新根节点D的左子节点

  3. 将D节点的左子节点B设置为原根节点A的右子节点

实现代码以下:

AVLNode<T> singleRightRotation(AVLNode<T> node) {
    AVLNode<T> result = node.getRight();
    AVLNode<T> left = result.getLeft();
    node.setRight(left);
    result.setLeft(node);
    return result;
}
复制代码

LL插入

当插入的节点在左子树的左节点上(GDB路径)

操做步骤:

  1. 将左子节点D做为根结点

  2. 原根节点G做为新根节点D的右子节点

  3. 将D节点的右子节点F做为原结点G的左子节点

实现代码:

AVLNode<T> singleLeftRotation(AVLNode<T> node) {
    AVLNode<T> result = node.getLeft();
    AVLNode<T> right = result.getRight();
    node.setLeft(right);
    result.setRight(node);
    return result;
复制代码

RL插入

当插入的节点在右子树的左节点上(ADB路径)

操做步骤:

  • 针对A节点的右子节点D作左旋转

  • 针对A节点作右旋转

实现代码:

AVLNode<T> doubleRightLeftRotation(AVLNode<T> node){
    AVLNode<T> right = singleLeftRotation(node.getRight());
    node.setRight(right);
    return singleRightRotation(node);
}
复制代码

LR插入

当插入的节点在右子树的左节点上(GDF路径)

操做步骤:

  • 针对G节点的左子节点D作右旋转

  • 针对G节点作左旋转

实现代码:

AVLNode<T> doubleLeftRightRotation(AVLNode<T> node) {
    AVLNode<T> left = singleRightRotation(node.getLeft());
    node.setLeft(left);
    return singleLeftRotation(node);
}
复制代码

删除节点

咱们在删除节点时,思路以下:

  • 叶子节点直接删除

  • 包含一个子节点,将子节点替换到父节点

  • 包含两个子节点,使用后继节点替换被删除节点,删除后继节点便可

平衡调整的思路:节点被删除后,至关于在兄弟节点插入新的节点

代码以下:

return null;
    }
    T nodeData = node.getData();
    int flag = data.compareTo(nodeData);
    if (flag > 0) { //右子树
        AVLNode<T> right = delete(node.getRight(), data);
        node.setRight(right);
        AVLNode<T> lNode = node.getLeft();
        int rHeight = getHeight(right);
        int lHeight = getHeight(lNode);
        int bf = lHeight - rHeight;
        if (bf == 2) {//右子树被删除节点,不平衡
            //查看左兄弟节点,若是左兄弟有右子节点高度大于左子节点须要进行左右旋转 (删除状况2)
            if (getRightNodeHeight(lNode) > getLeftNodeHeight(lNode)) {
                node = doubleLeftRightRotation(node);
            } else {    //右节点的高度小于或者等于左子节点的高度,左单旋便可(删除状况1)
                node = singleLeftRotation(node);
            }
        }
    } else if (flag < 0) { //左子树
        AVLNode<T> left = delete(node.getLeft(), data);
        node.setLeft(left);
        AVLNode<T> right = node.getRight();
        int lHeight = getHeight(node.getLeft());
        int rHeight = getHeight(right);
        int bf = rHeight - lHeight;
        if (bf == 2) {//左子树被删除节点,不平衡
            //查看右兄弟节点,若是左子节点高度大于右子节点高度,进行右左旋转 (删除状况4)
            if ( getLeftNodeHeight(right) > getRightNodeHeight(right)) {
                node = doubleRightLeftRotation(node);
            } else {
                //左子树的高度小于等于右子节点的高度,左单旋转便可(删除状况3)
                node = singleRightRotation(node);
            }
        }
    } else { //found
        if (Objects.nonNull(node.getLeft()) && Objects.nonNull(node.getRight())) {  //存在左右子节点
            AVLNode<T> rMin = findMin(node.getRight()); //后继节点替代
            node.setData(rMin.getData());
            delete(node.getRight(), rMin.getData());    //删除后继节点
        } else {
            node = Objects.isNull(node.getLeft()) ? node.getRight() : node.getLeft();
        }
    }
    if (Objects.nonNull(node)) {
        buildHeight(node);
    }
    return node;
}
复制代码

因为AVL是一个高度严格平衡的二叉搜索树,查找效率在log2n级别。可是在维护节点高度平衡时,须要进行旋转操做(插入时最多两次旋转;删除节点时AVL树须要调整整个查询路径的高度平衡,最多须要log2n次旋转)后面,咱们将介绍另一种平衡搜索二叉树(红黑树)!

引言

红黑树、B树、B+树,都是软件开发中一个比较难理解和掌握的知识点。他们的本质依然是平衡二叉搜索树。若是直接去学习红黑树、B树、B+树的知识点,无异于雾里看花。此次咱们从这些数据结构的底层逻辑设计出发,不牵扯任何代码层面上的内容。

二三四树

定义

  • 二节点

  • 一个key和左右两个连接;其中key大于左连接、小于右连接

  • 三节点

  • 包含两个key和三个连接(两个key分别称为key1和key2,key1小于key2)

  • 一、二、3三个子连接(子连接1的key小于根结点key一、子连接2的key大于根结点key1且小于根结点key二、子连接3的key大于根结点key2)

  • 四节点

  • 包含三个key和四个子连接(三个key分别为key一、key二、key3且从小到大排列)

  • 一、二、三、4三个子连接(子连接1的key小于根结点key一、子连接2的key大于根结点key1且小于根结点key二、子连接3的key大于根结点key2且小于根结点key三、子连接4的key大于根结点key3)

  • 上述的节点计数指子连接的数量,而非节点包含的key的数量

操做

因为二、三、4树的查询操做和二叉搜索树的操做一致,再也不赘叙。本次主要完成插入和删除的操做描述

能够参考前面,熟悉二叉树一些基本定义和操做

二叉搜索树(BST)

平衡二叉树(AVL)

插入

咱们把1-10的数字拆入到一棵234树中

依次插入一、二、3节点

插入4节点,须要将4节点分裂成3个2节点的操做

至此,插入逻辑介绍完毕

删除

节点的删除逻辑,和二叉树的删除逻辑区别不大。若是是叶子节点,能够直接删除;若是是非叶子节点,须要转换为后继/前驱节点的删除方式,全部均可以转换为极值的删除

非2节点的删除

2节点的删删除

对于2节点的删除,须要转换为三、4节点中节点的删除

父节点为非2节点,兄弟节点是2节点

父节点是非2节点,兄弟节点是非2节点

父节点是2节点,兄弟节点非2节点

父节点是2节点,兄弟节点也是2节点

至此,咱们的234树的插入和删除操做介绍完了。搞清楚234树的插入和删除操做将是后续红黑树、B树、B+树的前置条件。

红黑树

从上面的2-3-4树了解到底层原理和操做逻辑,但按照对应逻辑实现代码和各类状况的处理,却不容易。因此咱们要减小因为2-3-4树为了实现平衡,而致使的实现复杂度上升的状况。咱们如今使用普通的二叉树+颜色来表示2-3-4树(红黑树是多路平路查找树的一种实现)

红黑树的定义:

  • 红连接必须是左连接,根结点必须是黑色的

  • 不能同时存在两条连续的红连接

  • 任一空连接到根节点的路径上经历的黑色节点个数同样

下面咱们使用1-3的插入来观察红黑树是如何保持平衡的

根据上面根据上面的操做咱们能够发现红黑树对2-3-4树的实现原理:

  • 使用黑+红两个节点来实现3节点(如上图插入2后)

  • 使用三个黑色节点实现4节点(如上图插入3后)

节点对象的定义

RedBlackNode<T extends Comparable<T>> {

    /*颜色的常量定义 red:false black:true 新建节点默认为红色*/
    public static final boolean RED = false;

    public static final boolean BLACK = true;

    private T data;
    
    private RedBlackNode<T> left;

    private RedBlackNode<T> right;

    private boolean color;
}
复制代码

操做

咱们将红黑树的操做分开描述

查找

查找和普通的二叉搜索树一致,再也不赘叙。

能够参考二叉搜索树关于查找的部分

旋转和变色

左旋转

实现步骤:

  • 右子节点的颜色 = 原根结点的颜色

  • 根结点node做为右子节点的左子节点,刷新为红色节点

  • 将右子节点的左子节点设置为原根结点的右子节点

代码示例:

RedBlackNode<T> rotateLeft(RedBlackNode<T> node){
    RedBlackNode<T> right = node.getRight();
    right.setColor(node.isColor());

    RedBlackNode<T> middle = right.getLeft();
    node.setRight(middle);
    node.setColor(RedBlackNode.RED);
    right.setLeft(node);
    return right;
}
复制代码

右旋转

将根结点的左子节点替换到根结点,将左子节点做为根结点返回

实现步骤:

  • 左子节点的颜色 = 原根结点的颜色

  • 根结点node替换到左子节点的右子节点,刷新为红色节点

  • 将左子节点的右子节点设置为原根结点的左子节点

代码示例:

RedBlackNode<T> rotateRight(RedBlackNode<T> node){
    RedBlackNode<T> result = node.getLeft();
    result.setColor(node.isColor());

    RedBlackNode<T> resultRight = result.getRight();
    node.setLeft(resultRight);

    result.setRight(node);
    node.setColor(RedBlackNode.RED);
    return result;
}
复制代码

变色

/**若是左右节点都是红色的那么将左右子节点修改成黑色,父节点修改成红色*/
void flushColor(RedBlackNode<T> node){
    node.setColor(RedBlackNode.RED);
    RedBlackNode<T> left = node.getLeft();
    left.setColor(RedBlackNode.BLACK);
    RedBlackNode<T> right = node.getRight();
    right.setColor(RedBlackNode.BLACK);
}
复制代码

插入

向2节点插入

向3节点插入

插入算法代码示例:

RedBlackNode<T> insert(RedBlackNode<T> node, T data){
      if (Objects.isNull(node)) {
        node = new RedBlackNode<>();
        node.setData(data);
        node.setColor(RedBlackNode.RED);
        return node;
    }
    T nodeData = node.getData();
    int flag = data.compareTo(nodeData);
    if (flag < 0) { //插入数据小于节点数据,入左子树
        RedBlackNode<T> left = insert(node.getLeft(), data);
        node.setLeft(left);
    } else if (flag > 0) {  //插入数据大于节点数据,入右子树
        RedBlackNode<T> right = insert(node.getRight(), data);
        node.setRight(right);
    }
    //插入位置在右子节点,且左子树非红色,进行左旋转
    if (isRed(node.getRight()) && !isRed(node.getLeft())) {
        node = rotateLeft(node);
    }
    //插入的节点在左子树的左子节点上,右旋
    if (isRed(node.getLeft()) && isRed(node.getLeft().getLeft())) {
        node = rotateRight(node);
    }
    if (isRed(node.getLeft()) && isRed(node.getRight())) {
        flushColor(node);
    }
    return node;
}
复制代码

删除

因为咱们在二叉搜索树BST里介绍过,咱们能够将节点删除的逻辑调整为极值的删除

2-3-4树文章里,已经知道单独的2节点是不能直接删除的,须要将2节点转换为3或4节点(2节点对应红黑树中的黑色节点)

综上所述:咱们须要极大/小值的删除和2节点的删除方法

删除最小值

主要分为3节点和4节点删除最小值(其中4节点根结点有红或黑两种颜色。CASE比较多,请放大查看)

代码示例:

/**
最小值的删除方法,返回删除后的根节点
*/
RedBlackNode<T> deleteMin(RedBlackNode<T> node){
    RedBlackNode<T> left = node.getLeft();
    //左节点不为null,最小值在node的左节点,继续向左
    if (Objects.isNull(left)) {
        return null;
    }
    //左右节点都不是红色,须要将黑色节点调整为红色Del-2至Del-5示
    RedBlackNode<T> ll = left.getLeft();
    if (!isRed(left) && !isRed(ll)) {
        node = removeRedLeft(node);
    }
    left = deleteMin(node.getLeft());
    node.setLeft(left);
    return blance(node);
}
/** 移除红色最小节点
*/
RedBlackNode<T> removeRedLeft(RedBlackNode<T> node) {
    flipsColor(node);
    RedBlackNode<T> right = node.getRight();
    RedBlackNode<T> rl = Objects.isNull(right) ? null : right.getLeft();
    //若是右左节点是红色节点(对应图中的Del-三、Del-5图)
    if (isRed(rl)) {
        right = rotateRight(right);
        node.setRight(right);
        node = rotateLeft(node);
    }
    return node;
}

/**变色Del-2至Del-5示*/
void flipsColor(RedBlackNode<T> node) {
    node.setColor(RedBlackNode.BLACK);
    RedBlackNode<T> left = node.getLeft();
    RedBlackNode<T> right = node.getRight();
    if (Objects.nonNull(left)) {
        left.setColor(RedBlackNode.RED);
    }
    if (Objects.nonNull(right)) {
        right.setColor(RedBlackNode.RED);
    }
}

/**
节点删除后的平衡调整方法
*/
RedBlackNode<T> balance(RedBlackNode<T> node){
    if (isRed(node.getRight())) {       //右节点为红,左旋(图中的2列)
        node = rotateLeft(node);
    }
    if (isRed(node.getRight()) && !isRed(node.getLeft())) {
        node = rotateLeft(node);
    }
    if (isRed(node.getLeft()) && isRed(node.getLeft().getLeft())) {
        node = rotateRight(node);
    }
    if (isRed(node.getLeft()) && isRed(node.getRight())) {
        flushColor(node);
    }
    return node;
}
复制代码

删除最大值

最大值的删除逻辑以下图示

代码示例:

/**
最大值的删除方法,返回删除后的根节点
*/
RedBlackNode<T> deleteMax(RedBlackNode<T> node){
    if(isRed(node.getLeft())){
        node = rotateRight;
    }
    RedBlackNode<T> right = node.getRight();
    if(right == null){
        return null;
    }
    if (!isRed(right) && !isRed(right.getLeft())) {
        node = removeRedRight(node);
    }
    right = deleteMax(right);
    node.setRight(right);
    return balance(node);
}
/** 移除红色右节点
*/
RedBlackNode<T> removeRedRight(RedBlackNode<T> node) {
    flipsColor(node);
    RedBlackNode<T> left = node.getLeft();
    RedBlackNode<T> lr = Objects.isNull(left) ? null : left.getRight();
    //若是左右节点是红色节点
    if (!isRed(rl)) {
        return rotateRight(node);
    }
    return node;
}
复制代码

删除

咱们将以上两个方法结合就能够获得红黑树的删除方法,再也不赘叙。

至此,咱们就将二叉搜索树的内容介绍完毕了。若是你以为对你有帮助,记得点个赞和在看哦。同时也期待你们的留言讨论。

欢迎关注公众号:javascript艺术

相关文章
相关标签/搜索