day42周三_chap-Collection_1.红黑树(还差旋转需要补充)

所谓红黑树,需要用一个红黑树例子结合红黑树特点来进行说明。这是一个具体对象先出现、后解释的概念,别把自己困在概念里。

第一步:颜色分红黑

第二步:根结点是黑色,所谓nil结点是方框NIL是黑色

第三步:如果一个结点是红色的,比如这个图里的10号、120号,那么它的子结点都是黑色的

(问题1:红色结点如果只有一个子结点,另一个是NIL,是正确的结构吗)

比如这个(40号结点右边是个NIL)

第四步:每个结点到所有后代叶子结点的简单路径上,均包含数目相同的黑色结点

这个图画得比较平衡,

40号红色结点叶子1的简单路径有2个黑色结点:20号黑色、叶子1

还是40号结点,叶子2的简单路径有2个黑色结点:20号黑色、叶子2

红黑树定义完,下面就是其他几个问题:

1.所谓黑色高度平衡(已经在上面第四步说明)

2.红色:结点是红色还是边是红色

(之所以有这个问题是有一个图,把结点之间的边标红,自己无法分辨)

(后来明白了:2-3-4数的2元素结点和3元素结点要分成二叉形式,其中有两个子分支的叉是标红色的)

3.2-3-4树引出红黑树概念

红黑树是一种特殊的二叉搜索树,是自平衡的,叶子结点层次高度差不超过1

2-3-4树:普通二叉树扩展,结点可以有:1 or 2 or 3 个元素(键),结点往下的分支可以有 2 or 3 or 4 个

树的基本操作:

(1).查找:找到对应的区间

(2).添加:找到区间以后,在叶子层插入

例子:2元素结点变3元素结点

临界例子:4结点,父结点是3元素结点,叶子分支4个都有元素,新的结点没地方插入

需要分裂父结点

这里介绍的是自底向上(叶子先填进来,再往上检查),下面介绍自上向底(叶子进来之前检查,保证叶子进来一定放得下)

遇到3个元素(4分支)的结点,先向上分裂再向下添加叶子

4.代码实现红黑树、2-3-4树的具体语句

通过伪代码发现直接实现分裂,步骤繁琐,所以有人设计出左倾红黑树,方便操作:

LLRBT(Left-Leaning-Red-Black-Tree)

实际流程是:2-3-4树 转化 左倾的红黑树,先变二叉结构,然后结点分裂让左元素下沉右元素上移(左下右上)

先把2元素结点、3元素结点转化成二叉结构。具体表现:

(情况1)2元素结点,有三个分支,分成2个分支:2 + 1

子结点1:2个孙子分支,红色

子结点2:1个孙子分支

(情况2)3元素结点,有四个分支,分成2个分支(均分):2 + 2

子结点1:2个孙子分支,红色

子结点2:2个孙子分支,红色

代码:

package com.cskaoyan.day13;

import sun.reflect.generics.tree.Tree;

import javax.swing.tree.TreeNode;
import java.util.TreeMap;

/**
 * @author cskaoyan
 * @Description
 * @create 2020-08-25 9:59
 */
public class RedBlackTree<K  extends Comparable<K>,   V> {

    private static final  boolean RED = true;
    private static final  boolean BLACK = false;
    // 根节点
    private TreeNode root;


    class TreeNode{
        // 红黑树中节点的key
        K key;
        // 红黑树中节点的value
        V value;
        // 红黑树中节点的左右子树
        TreeNode  left, right;
        // 红黑树中节点的颜色
        boolean color;
        // 记录该节点作为根节点的树中所有元素个数
        int size;

        public TreeNode(K key, V value, TreeNode left, TreeNode right, boolean color, int size) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
            this.color = color;
            this.size = size;
        }
    }


    /**
     * 在红黑树中: 根据key, 查找某个key对应的value(它和普通的二叉搜索树查找没有区别)
     * @param k
     * @return
     */
    public V get(K k){
        if (root == null) throw new RuntimeException("tree is null");
        if (k == null) throw new IllegalArgumentException("param is null");


        TreeNode x = root;
        while (x != null){
            int com = k.compareTo(x.key);

            if (com > 0) x = x.right;
            else if (com < 0)  x = x.left;
            else return x.value;
        }
        return null;
    }


    private  TreeNode rotatalLeft(TreeNode h){
        TreeNode x = h.right;
        h.right = x.left;
        x.left = h;
        x.color = h.color;
        h.color = RED;

        //size的转变
        x.size = h.size;
        h.size = h.left.size + h.right.size + 1;
        return x;
    }

    private  TreeNode rotatalRight(TreeNode h){
        TreeNode x = h.left;
        h.left = x.right;
        x.right = h;
        x.color = h.color;
        h.color = RED;
        //size的转变
        x.size = h.size;
        h.size = h.left.size + h.right.size + 1;
        return x;
    }

    /**
     * 该方法: 是用来分裂节点的
     * (2-3-4(4节点): 中间节点上移分裂,
     * 红黑树体现: 分裂上去的节点和别的上层节点构成一个节点, 所以上移节点要变成红色
     * 分裂留到下层的元素, 变成黑色
     * )
     * @param x
     * @return
     */
    private TreeNode colorFlip(TreeNode x){
        x.color = !x.color;
        x.left.color = !x.left.color;
        x.right.color = !x.right.color;
        return x;
    }

    /**
     * 添加操作
     * @param key
     * @param value
     * @return
     */
    public boolean put(K key, V value){

        int oldSize = root.size;
        root = insert(root, key, value);
        root.color = BLACK;

        check();

        return  oldSize < root.size;
    }



    private TreeNode insert(TreeNode root, K key, V value){
        if (root == null) return new TreeNode(key, value, null, null, RED, 1);

        int com = key.compareTo(root.key);
        if (com > 0){
            root.right = insert(root.right, key, value);
        } else if (com < 0){
            root.left = insert(root.left, key, value);
        } else {
            // TODO : 表述新插入的元素存在相等的key
            root.value = value;
        }
        root = fixUp(root);
        return root;
    }

    /**
     * 判断某个节点是不是红色
     * @param root
     * @return
     */
    private boolean isRed(TreeNode root) {
        if (root == null) return false;
        return  root.color == RED;
    }


    /**
     * 为了检查已经做过操作的红黑树: 是不是标准的
     */
    private void check() {

        //TODO 判断该树是不是23树(条件: 1,右子不能红:应该分裂 2:左不红色能连续红)
        boolean is23 = is23(root);

        //TODO 判断该树是不是平衡(获得某一黑叶子节点高, 判断其它叶子是否和这个高相等:通过减减操作)
        boolean isBalanced = isBalanced(root);


        if (!is23 || !isBalanced  ){
            throw new RuntimeException("tree is not Red-Black-Tree");
        }
    }

    /**
     * 判断某一个红黑树: 是不是平衡的
     * @param root
     * @return
     */
    private boolean isBalanced(TreeNode root) {
        if (root == null) return  true;

        TreeNode x = root;
        int height = 0;
        while (x != null) {
            if (!isRed(x)){
                height++;
            }

            x = x.left;
        }

        boolean isBalanced = isBalanced(root, height);
        return isBalanced;
    }

    // 递归方法
    private boolean isBalanced(TreeNode root, int height) {
        if (root == null) return height == 0;

        if (!isRed(root)){
            height--;
        }

        boolean balancedLeft = isBalanced(root.left, height );
        boolean balancedRight = isBalanced(root.right, height );

        return balancedLeft && balancedRight;
    }


    /**
     * 判断我们的红黑树是不是2-3树(不能让他是2-3-4树; 新为4节点要分裂)
     * @param root
     * @return
     */
    private boolean is23(TreeNode root) {
        if (root == null) return true;

        // 右子不能红:应该分裂
        // 左不红色能连续红)
        if (isRed(root.right)){
            return false;
        }

        if (isRed(root.left) && isRed(root.left.left)){
            return false;
        }

        boolean left = is23(root.left);
        boolean right = is23(root.right);

        return left && right;
    }


    /**
     * 保证当右侧的节点是2节点的时候, 那么通过变换旋转, 让他变为非2节点
     * @param h
     * @return
     */
    private TreeNode moveRedRight(TreeNode h){
        colorFlip(h);
        if (isRed(h.left.left)){
            h = rotatalRight(h);
            colorFlip(h);
        }
        return h;
    }

    private TreeNode moveRedLeft(TreeNode h){
        colorFlip(h);
        if (isRed(h.right.left)){

            // 先把h.right 右旋
            h.right = rotatalRight(h.right);
            // 再把整体节点左旋
            h = rotatalLeft(h);

            colorFlip(h);
        }
        return h;
    }


    public void removeMax(){
        if (root == null) throw new RuntimeException("tree is null");

        root = removeMax (root);
        root.color = BLACK;

    }

    private TreeNode removeMax(TreeNode root) {

        // 如果左节点是红色节点, 那么右旋转
        if (isRed(root.left)) rotatalRight(root);

        // 如果右子节点为null, 说明该节点, 一定是最大节点
        if (root.right == null) return null;

        if (!isRed(root.right) && !isRed(root.right.left)){
          // root 的右节点一定是 2 节点
            root = moveRedRight(root);
        }
        root = fixUp(root);
        root.right = removeMax(root.right);
        return root;
    }

    public void removeMin(){
        if (root == null) throw new RuntimeException("tree is null");
        root = removeMin (root);
        root.color = BLACK;
    }

    private TreeNode removeMin(TreeNode root) {

        if (root.left == null) return null;

        if (!isRed(root.left) && !isRed(root.left.left)){

            root = moveRedLeft(root);
        }
        // 修复删除过程中的变换
        root = fixUp(root);
        root.left = removeMin(root.left);
        return root;
    }


    public boolean delete(K key){
        if (root == null) throw new RuntimeException("tree is null");
        if (key == null) throw new RuntimeException("key is null");

        int oldSize = root.size;

        root = delete(root, key);

        return oldSize < root.size;
    }

    private TreeNode delete(TreeNode root, K key) {
        int com = key.compareTo(root.key);

        if (com < 0){// 移动到left子树上执行删除操作
            if (!isRed(root.left) && !isRed(root.left.left)){
                root = moveRedLeft(root);
            }

            root.left = delete(root.left, key);
        }else {

            if (isRed(root.left)){
                root = rotatalRight(root);
            }

            if (key.compareTo(root.key) == 0 && root.right == null) return null;

            if (!isRed(root.right) && !isRed(root.right.left)){
                root = moveRedRight(root);
            }

            if (key.compareTo(root.key) == 0){

                //
                TreeNode target = minRight(root.right);
                root.value = target.value;
                root.key = target.key;


                root.right = removeMin(root.right);

            } else {
                root.right = delete(root.right, key);
            }
        }

        root = fixUp(root);

        root.size = root.left.size + root.right.size + 1;
        return root;

    }

    private TreeNode minRight(TreeNode right) {

        while (right.left != null ){
            right = right.left;
        }
        return right;
    }


    private TreeNode fixUp(TreeNode root) {
        // 修正红黑树
        if (isRed(root.right)) root = rotatalLeft(root);
        if (isRed(root.left) && isRed(root.left.left)) root = rotatalRight(root);
        // TODO: 放到这个位置, 保证在红黑树中插入完成之后不存在: 四节点
        // 判断该节点的左右子节点是不是红色的,
        // 如果是红色的, 说明对应2-3-4树种的4节点(3个key), 需要向上分裂
        if (isRed(root.left) && isRed(root.right)) colorFlip(root);
        // 改变整体的size
        root.size = root.left.size + root.right.size + 1;
        return root;
    }


}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值