数据结构(十 一) ---[实现红黑树(Red Black Tree)]

2-3树

首先23树是满足二分搜索树的性质;
节点可以存放一个或两个元素

在这里插入图片描述

例如这样一棵2-3树;
2-3树是绝对的平衡树

在这里插入图片描述

例如,现在给出这样一个数组,请将它整理为二分搜索树,以及 2-3 树
[12,23,6,9,45,36,86,25,46]

二分搜索树–>

在这里插入图片描述

[12,23,6,9,45,36,86,25,46]
2-3树形成过程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

最后一步,添加节点46;

在这里插入图片描述

红黑树与2-3树的等价性

由于节点属性的话,线条颜色不好处理;那么就就节点的红黑表示红黑树中的关系;
红色节点是左倾斜的;

在这里插入图片描述

比如要把下面这棵2-3树变为红黑树

在这里插入图片描述

走到3节点17与33这块,17分离出去,

在这里插入图片描述

分离出的节点17的左子树也是个3节点,同样,分离

在这里插入图片描述

然后将3节点66与88分离
在这里插入图片描述
最终,整理左右关系;得到红黑树;

在这里插入图片描述

红黑树

  • 红黑树的根结点为黑色;叶子节点为黑色;
  • 若一个节点为红色节点,则它的子节点都为黑色节点;
  • 由任意节点到叶子节点,经过的黑色节点个数是一样的;

来感受一下构建红黑树时添加节点的过程;

添加节点时,默认为红色节点;

首先添加节点42,更新根节点后,节点42置为黑色节点;

在这里插入图片描述

然后添加节点37,根据二分搜索树特性,它将被挂接到根结点42的左边;

在这里插入图片描述

试想一下,若先添加了节点37;然后再去添加节点42呢;
由于不符合红黑树的性质,就得需要左旋处理;并且颜色转换处理;

在这里插入图片描述

左旋转与颜色变换

那么来具体看看这个转换过程;
(其余节点临时添加上去,为演示左旋转效果)

在这里插入图片描述

颜色变换;
首先想一下在2-3树中的效果; 节点37节点42是一个融合的3节点;

在这里插入图片描述

颜色翻转

在添加节点37和节点42后;

oK,接着添加节点66;

在这里插入图片描述

在2-3树中的效果是—>

在这里插入图片描述

考虑到节点42可能会向上融合其他节点成为3结点,所以它得是红色的;
要是这个结点没有向上融合的话(也就是说这个结点是根结点喽),不必担心;
在写添加方法的时候已经考虑到了这个问题,将所有结点添加完成后,会将树的根节点置为黑色的;

//颜色反转处理;
    private void colorFlip(TreeNode node){
        //当前节点置为红色;(考虑到这个node节点可能向上融合;而融合节点为红色的)
        node.isRed = true;
        //子节点置为黑色;
        node.left.isRed  = false;
        node.right.isRed = false;
    }

在这里插入图片描述

右旋转与颜色变换;

OK,刚才是添加节点66的状况;我这里要是添加节点12呢;
在节点42和节点37的基础上;

在这里插入图片描述

在2-3树中的效果

在这里插入图片描述

就得考虑右旋转了;颜色变换,以及节点的颜色翻转;
这里也同样的,用几个临时节点参与演示效果;

在这里插入图片描述

特殊情况处理

OK,刚才是添加节点12的状况;我这里要是添加节点40呢;
在节点42和节点37的基础上;

在这里插入图片描述

具体操作
在这里插入图片描述

实现红黑树

/**
 * @author by 小智RE0
 * @date 2021-12-19
 * 红黑树
 */
public class RedBlackTree<T extends Comparable<T>> {
    //内部类节点;
    class TreeNode {
        //节点值;
        T val;
        //左节点;
        TreeNode left;
        //右结点;
        TreeNode right;
        //是否为红色节点;true:红色节点;false:黑色节点;
        boolean isRed;

        //初始化;
        public TreeNode(T val) {
            this.val = val;
            this.left = null;
            this.right = null;
            //节点默认为红色;
            this.isRed = true;
        }
    }

    //头结点;
    private TreeNode root;

    //定义树结点的个数;
    private int size;

    public RedBlackTree() {
        this.root = null;
        this.size = 0;
    }

    //判空;
    public boolean isEmpty() {
        return this.root == null;
    }


    //辅助方法;获取节点的颜色; 注意,根据属性isRed;true红色节点;false:黑色节点;
    private boolean getColor(TreeNode node) {
        if (node == null) return false;

        //根据节点的属性获取;
        return node.isRed;
    }

    //颜色反转处理;
    private void colorFlip(TreeNode node) {
        //当前节点置为红色;(考虑到这个node节点可能向上融合;而融合节点为红色的)
        node.isRed = true;
        //子节点置为黑色;
        node.left.isRed = false;
        node.right.isRed = false;
    }


    //左旋处理;且变换节点颜色;
    /*
     *     Node                   x
     *    /    \     左旋        /   \
     *   n1     x    ==>>     Node   n3
     *         / \           /  \
     *        n2  n3        n1  n2
     * */
    private TreeNode rotateLeft(TreeNode node) {
        //首先取出节点x,与x的左子节点;
        TreeNode x = node.right;
        TreeNode n2 = x.left;
        x.left = node;
        node.right = n2;
        //颜色变换;
        x.isRed = getColor(node);
        node.isRed = true;

        return x;
    }

    //右旋转处理,且变换节点的眼色;
    /*
     *     Node                   y
     *    /    \     右旋        /   \
     *   y     n3    ==>>     n1    Node
     *  / \                        /  \
     *n1  n2                      n2  n3
     * */
    public TreeNode rotateRight(TreeNode node) {
        //首先取出节点y,与y的右子节点;
        TreeNode y = node.left;
        TreeNode n2 = y.right;

        y.right = node;
        node.left = n2;
        //颜色变换;
        y.isRed = getColor(node);
        node.isRed = true;

        return y;
    }


    //添加元素;
    public void add(T ele) {
        //判断是否存在;
        if (contains(ele) != null) {
            return;
        }
        //每次将创建的根节点返回;
        root = add(root, ele);
        //添加之后,让根结点变为黑色;
        root.isRed = false;
        this.size += 1;
    }

    //递归添加元素的底层;
    private TreeNode add(TreeNode node, T ele) {
        //不存在就创建;
        if (node == null) {
            return new TreeNode(ele);
        }
        //添加的元素和之前的根结点进行比较;
        if (ele.compareTo(node.val) > 0) {
            node.right = add(node.right, ele);
        } else {
            node.left = add(node.left, ele);
        }

        //红黑树操作;
        //若右树为红色时,左旋转;
        if (!getColor(node.left) && getColor(node.right)) {
            node = rotateLeft(node);
        }

        //若左树为红色,左树的左树为红色时;
        if (getColor(node.left) && getColor(node.left.left)) {
            node = rotateRight(node);
        }

        //左树和右树都是红色时,进行颜色反转;
        if (getColor(node.left) && getColor(node.right)) {
            colorFlip(node);
        }

        return node;
    }


    //查询元素;
    public TreeNode contains(T ele) {
        if (root == null) {
            return null;
        }
        return contains(root, ele);
    }

    //查询元素的底层;
    private TreeNode contains(TreeNode node, T ele) {
        //递归结束点;
        if (node == null) {
            return null;
        }
        //将当前根结点的值存储;
        T val = node.val;
        if (ele.compareTo(val) == 0) {
            return node;
        } else if (ele.compareTo(val) > 0) {
            return contains(node.right, ele);
        } else {
            return contains(node.left, ele);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小智RE0

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

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

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

打赏作者

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

抵扣说明:

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

余额充值