【数据结构三】RBTree红黑树代码测试, 添加 ,删除

6.5测试类

添加测试类1TreeOperation
package com.ccc.util.treemap;


public class TreeOperation {
    /*
    树的结构示例:
              1
            /   \
          2       3
         / \     / \
        4   5   6   7
    */

    // 用于获得树的层数
    public static int getTreeDepth(RBTree.RBNode root) {
        return root == null ? 0 : (1 + Math.max(getTreeDepth(root.getLeft()), getTreeDepth(root.getRight())));
    }


    private static void writeArray(RBTree.RBNode currNode, int rowIndex, int columnIndex, String[][] res, int treeDepth) {
        // 保证输入的树不为空
        if (currNode == null) return;
        // 0、默认无色
//       res[rowIndex][columnIndex] = String.valueOf(currNode.getValue());
        //1、颜色表示
        if(currNode.isColor()){//黑色,加色后错位比较明显
                res[rowIndex][columnIndex] = ("\033[30;3m" + currNode.getValue()+"\033[0m") ;
        }else {
                res[rowIndex][columnIndex] = ("\033[31;3m" + currNode.getValue()+"\033[0m") ;
        }
        //2、R,B表示
//        res[rowIndex][columnIndex] = String.valueOf(currNode.getValue()+"-"+(currNode.isColor()?"B":"R")+"");

        // 计算当前位于树的第几层
        int currLevel = ((rowIndex + 1) / 2);
        // 若到了最后一层,则返回
        if (currLevel == treeDepth) return;
        // 计算当前行到下一行,每个元素之间的间隔(下一行的列索引与当前元素的列索引之间的间隔)
        int gap = treeDepth - currLevel - 1;
        // 对左儿子进行判断,若有左儿子,则记录相应的"/"与左儿子的值
        if (currNode.getLeft() != null) {
            res[rowIndex + 1][columnIndex - gap] = "/";
            writeArray(currNode.getLeft(), rowIndex + 2, columnIndex - gap * 2, res, treeDepth);
        }

        // 对右儿子进行判断,若有右儿子,则记录相应的"\"与右儿子的值
        if (currNode.getRight() != null) {
            res[rowIndex + 1][columnIndex + gap] = "\\";
            writeArray(currNode.getRight(), rowIndex + 2, columnIndex + gap * 2, res, treeDepth);
        }
    }


    public static void show(RBTree.RBNode root) {
        if (root == null) System.out.println("EMPTY!");
        // 得到树的深度
        int treeDepth = getTreeDepth(root);

        // 最后一行的宽度为2的(n - 1)次方乘3,再加1
        // 作为整个二维数组的宽度
        int arrayHeight = treeDepth * 2 - 1;
        int arrayWidth = (2 << (treeDepth - 2)) * 3 + 1;
        // 用一个字符串数组来存储每个位置应显示的元素
        String[][] res = new String[arrayHeight][arrayWidth];
        // 对数组进行初始化,默认为一个空格
        for (int i = 0; i < arrayHeight; i ++) {
            for (int j = 0; j < arrayWidth; j ++) {
                res[i][j] = " ";
            }
        }

        // 从根节点开始,递归处理整个树
        // res[0][(arrayWidth + 1)/ 2] = (char)(root.val + '0');
        writeArray(root, 0, arrayWidth/2, res, treeDepth);

        // 此时,已经将所有需要显示的元素储存到了二维数组中,将其拼接并打印即可
        for (String[] line: res) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < line.length; i ++) {
                sb.append(line[i]);
                if (line[i].length() > 1 && i <= line.length - 1) {
                    i += line[i].length() > 4 ? 2: line[i].length() - 1;
                }
            }
            System.out.println(sb.toString());
        }
    }
}
2添加测试类2RBTreeTest
package com.ccc.util.treemap;

import java.util.Scanner;


public class RBTreeTest {
    public static void main(String[] args) {
        //新增节点
//        insertOpt();
        //删除节点
        deleteOpt();
    }

    /**
     * 插入操作
     */
    public static void insertOpt(){
        Scanner scanner=new Scanner(System.in);
        RBTree<String,Object> rbt=new RBTree<>();
        while (true){
            System.out.println("请输入你要插入的节点:");
            String key=scanner.next();
            System.out.println();
            //这里代码最多支持3位数,3位以上的话红黑树显示太错位了,这里就不重构代码了,大家可自行重构
            if(key.length()==1){
                key="00"+key;
            }else if(key.length()==2){
                key="0"+key;
            }
            rbt.put(key,null);
            TreeOperation.show(rbt.getRoot());
        }
    }

    /**
     * 删除操作
     */
    public static void deleteOpt(){
        RBTree<String,Object> rbt=new RBTree<>();
        //测试1:预先造10个节点(1-10)
        String keyA=null;
        for (int i = 1; i <11 ; i++) {
            if((i+"").length()==1){
                keyA="00"+i;
            }else if((i+"").length()==2){
                keyA="0"+i;
            }
            rbt.put(keyA,null);
        }

        //测试2:包含2位数和3位数的测试代码 1 2 3 4 5 66 77 88 99 100 101
        rbt.put("001",null);
        rbt.put("002",null);
        rbt.put("003",null);
        rbt.put("004",null);
        rbt.put("005",null);
        rbt.put("066",null);
        rbt.put("077",null);
        rbt.put("088",null);
        rbt.put("099",null);
        rbt.put("100",null);
        rbt.put("101",null);

        TreeOperation.show(rbt.getRoot());
        //以下开始删除
        Scanner scanner=new Scanner(System.in);
        while (true){
            System.out.println("请输入你要删除的节点:");
            String key=scanner.next();
            System.out.println();
            //这里代码最多支持3位数,3位以上的话红黑树显示太错位了,这里就不重构代码了,大家可自行重构
            if(key.length()==1){
                key="00"+key;
            }else if(key.length()==2){
                key="0"+key;
            }
            //1 2 3 88 66 77 100 5 4 101
            rbt.remove(key);
            TreeOperation.show(rbt.getRoot());
        }
    }
}
3, RBTree
package com.ccc.util.treemap;

public class RBTree<K extends Comparable<K>, V> {
    //红色用false来表示
    private static final boolean RED = false;
    private static final boolean BLACK = true;

    //红黑树的root节点
    private RBNode root;

    public RBNode getRoot() {
        return root;
    }

    public void setRoot(RBNode root) {
        this.root = root;
    }

    /**
     * 实现左旋
     *      p                          pr
     *      /\                        /\
     *     pl  pr    ==>       p      rr
     *          /\              /\
     *         rl  rr         pl   rl
     *  左旋操作:
     *  不用变的:  p-pl , pr-rr
     *  需要调整:  1. pr-rl 调整为  p-rl ,
     *                    将rl调整为p的右子节点
     *                    将p调整为rl的父节点
     *                2.判断p是否有父节点
     *                有:  把pr.parent = p.parent
     *                     p为p.parent的子节点, 到底是 左还是右呢
     *                       if p.parent.left == p
     *                           p.parent.left = pr
     *                       else
     *                           p.parent.right = pr
     *                没有: 直接把pr设置成root节点
     *                3.最后  把p 和 pr交换
     *                p.parent = pr;  pr.left = p
     *
     * @param p, 需要旋转的节点
     */
    //左旋方法
    private  void  leftRotate(RBNode p){
        if ( p != null ){
            //获取到pr节点
            RBNode pr = p.right;
            //获取到pr的左子节点 rl
            p.right =pr.left;
//            pr = rl;
            if ( pr.left != null ) {
                //将rl调整为p的右子节点
//                p.right = rl;
                //将p调整为rl的父节点
                pr.left.parent = p;
            }
            //2,判断p是否有父节点
            pr.parent = p.parent; //不管p是否有父节点, 都设置为pr的父节点
            if ( p.parent == null ){
                //如果p.parent 为空, 说明p为root节点, 把root改为pr
                root = pr ;
                //如果p是p.parent的左子节点, 就变更为p.parent.left  = pr
            }else  if ( p.parent.left == p ){
                p.parent.left = pr;
            }else {//如果p是p.parent的右子节点, 就变更为p.parent.right  = pr
                p.parent.right = pr;
            }
            //3 最后 把p父节点设置为pr, pr的左子节点设置为p
            pr.left = p;
            p.parent = pr;
        }
    }

    /**
     * 右旋实现
     *      p                 pl
     *      /\                /\
     *    pl  pr    ==>    ll    p
     *    /\                    /\
     *   ll lr               lr   pr
     * 不变的 p-pr , pl-lr,  两个2节点的右字节点不变
     * 步骤1: p-pl 变成 p-lr
     * 步骤2: 判断p是否有父节点 , pl-lr 变成 pr-p
     * 步骤3:  p-pl 变成 pl-p
     * @param p
     */
    //右旋方法
    private  void  rightRotate(RBNode p){
        if (p != null) {
            RBNode pl = p.left;
            p.left = pl.right;
            //步骤1: p-pl 变成 p-lr , lr的父节点 = p
            if (pl.right != null) {
//                p.left = lr;
                pl.right.parent = p;
            }
            //步骤2: 判断p是否有父节点,
            pl.parent = p.parent ;
            if (p.parent == null) {
                root = pl;
            }else if ( p.parent.left == p ){
                p.parent.left = pl;
            }else {
                p.parent.right = pl;
            }
            //步骤3:  p-pl 变成 pl-p
            pl.right = p;
            p.parent = pl;
        }
    }
    //插入操作
    public void put(K key,V value){
        //1, 找到插入的父节点
        RBNode t = root;
        if ( t == null ){ //这种情况说明是第一次插入
            root = new RBNode(null,key,value==null?key:value);
            return;
        }
        //记录比较情况
        int cmp;
        RBNode parent;
        if (key == null){
            System.out.println("put 命令里 key 为空了");
            throw new NullPointerException();
        }
        do {
            parent = t;
            //比较当前根节点与传入的key大小来决定从哪边开始查找
            cmp = key.compareTo((K) t.key);
            if ( cmp > 0){ //从右侧查找
                t = t.right ;
            }else if ( cmp < 0 ){//从左侧查找
                t = t.left ;
            }else {// cmp =0 说明key相等了
                //如果value为空就设置为key
                t.setValue( value == null ? key:value);
                return;
            }
        }while (t != null);
        //2, 将新节点添加到父节点的子节点中
        // a 创建要插入的节点
        RBNode node = new RBNode(parent, key, value == null ? key : value);
        if ( cmp > 0 ){
            //如果比父节点大, 就放到右边
            parent.right = node;
        }else {
            parent.left = node;
        }
        //旋转和变色 调整红黑树的平衡
        fixAfterPut(node);
    }
    //获取父节点
    private RBNode getParent(RBNode node){
        return node != null ? node.parent : null;
    }
    //获取爷节点
    private RBNode getGrandfather(RBNode node){
        return node != null ? node.parent.parent : null;
    }
    //获取左节点
    private RBNode getLeft(RBNode node){
        return node != null ? node.left : null;
    }
    //获取右节点
    private RBNode getRight(RBNode node){
        return node != null ? node.right : null;
    }
    //获取父节点
    private boolean getColor(RBNode node){
        //如果传过来的节点是空的, 就返回黑色, ----------------Treemap里删除的时候会用到这个表达式
        return node == null ? BLACK : node.color;
    }
    //设置颜色
    private void setColor(RBNode node, boolean color){
        if (node != null) {
            node.color = color;
        }
    }
    /**
     * 插入放点后的调整操作
     * 2-3-4对应的操作
     *     2书点: 新插入一个元素直接2节点合并不用调整
     *    	 	红黑树:新增一个红色 放点在黑色节点下不需要调整
     *     3节点: 新插入一个元素在3节点下, 那么会出现6中情况(2两种不需要调整,4种需要调整)
     *     	红黑树: 插入的节点是 插入在上黑下红的结构中,插入在红色节点
     *     4节点:新插入一个元素在4节点下,那么会出现4中情况都需要调整
     *     	红黑树:新增的节点是红色, 爷爷节点是黑色,父亲节点和叔叔节点是红色
     * @param x
     */
    private void  fixAfterPut(RBNode<K,Object> x){
        //插入的节点  肯定是红色
        x.color = RED;
        //2节点不用调整, 3, 4 节点才需要调整, 把2节点过滤了
        while ( x !=null && x != root && x.parent.color ==RED ){ //为空为root都不需要调整, 只有2节点的父节点是黑色,其他都是红色, 所以这里把2节点排除了
            //这里分为了两种情况,
                if ( getParent(x) == getLeft(getGrandfather(x))  ){  //x的父节点在x爷爷左子节点时  对应 图1 , 2 ,5, 6
                    //需调整的变成了4种, 有叔叔节点: 图1,2     没有叔叔节点: 图5,6
                    //找到右叔叔节点, 1,2找到4 , 5,6 找到null
                    RBNode uncleR = getRight(getGrandfather(x));
                    //如果右叔叔的颜色是RED, 说明不为空 : 图 1,2
                    if (getColor(uncleR) == RED) {
                        //叔叔跟父亲变为黑色, 爷爷变成红色
                        //但是还有一种情况是爷爷节点上面还有元素, 这下就把(下面这个整体)爷爷节点当成x ,再来一遍 如图9
                        //变色+ 递归
                        setColor(uncleR,BLACK); //把右叔叔设置成黑色
                        setColor( getParent(x) , BLACK ); //把父节点设置成黑色
                        setColor(getGrandfather(x),RED);//把爷爷设置成红色
                        //递归处理,  就是先保证自身平衡, 再把这部分当做新元素和上面的节点变色处理
                        x = getGrandfather(x);

                    }else {
                        //说明没有右叔叔节点: 图 5,6
                        //判断x是父节点的左子节点还是右子节点
                        if ( x == getRight(getParent(x))) { //是父节点的右子节点: 图6
                            x = getParent(x);//现在x就转移到了2 , 如图10
                            leftRotate(x); // 旋转之后, 下面5, 和10 可以一起处理了
                        }
                        //把父节点变为黑色, 爷爷节点变为红色, 再根据爷爷节点右旋即可
                        setColor(getParent(x),BLACK);//父黑
                        setColor(getGrandfather(x),RED);//爷红
                        rightRotate(getGrandfather(x));//爷右旋
                    }
                }else {//x的父节点在x爷爷右子节点时  对应 图3,4,7,8
                    //需调整的变成了4种, 有叔叔节点: 图3,4     没有叔叔节点: 图7,8 , 和上面的情况左右相反
                    //找到左叔叔节点, 图3,4找到2 , 7,8 找到null
                    RBNode uncleL = getLeft(getGrandfather(x));
                    //如果左叔叔的颜色是RED, 说明不为空 : 图 3,4
                    if (getColor(uncleL) == RED) {
                        //叔叔跟父亲变为黑色, 爷爷变成红色
                        //但是还有一种情况是爷爷节点上面还有元素, 这下就把(下面这个整体)爷爷节点当成x ,再来一遍 如图9
                        //变色+ 递归
                        setColor(uncleL,BLACK); //把左叔叔设置成黑色
                        setColor( getParent(x) , BLACK ); //把父节点设置成黑色
                        setColor(getGrandfather(x),RED);//把爷爷设置成红色
                        //递归处理,  就是先保证自身平衡, 再把这部分当做新元素和上面的节点变色处理
                        x = getGrandfather(x);

                    }else {
                        //说明没有左叔叔节点: 图 7,8
                        //判断x是父节点的左子节点还是右子节点
                        if ( x == getLeft(getParent(x))) { //是父节点的右子节点: 图7
                            x = getParent(x);//现在x就转移到了3
                            rightRotate(x); // 旋转之后, 下面7, 和8 可以一起处理了
                        }
                        //把父节点变为黑色, 爷爷节点变为红色, 再根据爷爷节点右旋即可
                        setColor(getParent(x),BLACK);//父黑
                        setColor(getGrandfather(x),RED);//爷红
                        leftRotate(getGrandfather(x));//爷右旋
                    }
                }
        }
        // root 节点肯定为黑色
        setColor(root , BLACK);
    }

    //红黑树对象
    //继承Comparable接口, 可以做比较
    static class RBNode<K extends Comparable<K>,V>{
        //父节点
        private RBNode parent;
        //左子节点
        private RBNode left;
        //右子节点
        private RBNode right;
        //颜色,  这里定义的是 黑--true  红--false
        private boolean color;

        private  K key;

        private  V value;

        public RBNode() {

        }

        public RBNode(RBNode parent, RBNode left, RBNode right, boolean color, K key, V value) {
            this.parent = parent;
            this.left = left;
            this.right = right;
            this.color = color;
            this.key = key;
            this.value = value;
        }
        //为了操作简化, 再添加一个parent,key,value
        public RBNode(RBNode parent, K key, V value) {
            this.parent = parent;
            this.key = key;
            this.value = value;
        }

        public RBNode getParent() {
            return parent;
        }

        public void setParent(RBNode parent) {
            this.parent = parent;
        }

        public RBNode getLeft() {
            return left;
        }

        public void setLeft(RBNode left) {
            this.left = left;
        }

        public RBNode getRight() {
            return right;
        }

        public void setRight(RBNode right) {
            this.right = right;
        }

        public boolean isColor() {
            return color;
        }

        public void setColor(boolean color) {
            this.color = color;
        }

        public K getKey() {
            return key;
        }

        public void setKey(K key) {
            this.key = key;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }
    }

    /**
     * 找到前驱节点
     * @param node
     * @return
     */
    private RBNode getPrecursor(RBNode node){
        if (node == null  ) {
            return null;
        } else if (getLeft(node) != null) {
            //如果他的左节点不为空, 就循环找他的左节点的右子节点
            RBNode p = getLeft(node);
            while ( getRight(p) != null){
                p = getRight(p);
            }
            return  p;
        }else {
            //如果这个node没有左节点, 那么就向上找前驱节点
            //这种情况在 红黑树 ,2-3-4树中不会出现
            RBNode p = node.parent;
            RBNode n1 = node;
            while ( p!= null && n1 == getLeft(p)){
                n1 = p;
                p = getParent(p);
            }
            return p;
        }
    }
    /**
     * 找到后继节点
     * @param node
     * @return
     */
    private RBNode getSuccessor(RBNode node){
        if (node == null  ) {
            return null;
        } else if (getRight(node) != null) {
            //如果他的左节点不为空, 就循环找他的左节点的右子节点
            RBNode p = getRight(node);
            while ( getLeft(p) != null){
                p = getLeft(p);
            }
            return  p;
        }else {
            //如果这个node没有左节点, 那么就向上找前驱节点
            //这种情况在 红黑树 ,2-3-4树中不会出现
            RBNode p = node.parent;
            RBNode n1 = node;
            while ( p!= null && n1 == getRight(p)){
                n1 = p;
                p = getParent(p);
            }
            return p;
        }
    }

    /**
     * 删除节点
     *      1, 节点删除(可以看做普通的二叉树删除)
     *      2, 删除后调整
     * @param key
     * @return
     */
    public V remove(K key){
        //1. 根据需要删除的key, 找到对应的node节点
        RBNode node = getNode(key);
        if ( node == null ){
            return  null;
        }
        V oldValue = (V) node.value;
        //具体删除节点的方法
        deleteNode(node);
        return oldValue;
    }


    /**
     * 根据key找到删除的对应node
     * @param key
     * @return
     */
    private RBNode getNode(K key) {
//        if ( key == null ){
//            return null;
//        }
        RBNode node = root;
        while ( node != null ){
            //int cmp1 = node.key.compareTo(key);
            int cmp = key.compareTo((K) node.key);
            if (cmp > 0) {
               node = node.right ;
            } else if (cmp < 0) {
                node = node.left;
            }else {
                //找到了对应的节点
                return node;
            }
        }
        return null;
    }

    /**
     * 删除节点
     * 1.删除节点(普通的二叉树相同)
     *      a. 删除叶子节点, 直接删除
     *      b. 删除的节点有一个子节点, 用子节点来替代
     *      c. 删除的节点有两个子节点, 把这个节点赋值给前驱或后继节点, 再删除掉前去后继节点
     *      将情况c转换成情况a, b
     * 2.调整
     * @param node
     */
    private void deleteNode(RBNode node) {
        //1, 先处理情况3
        if (getLeft(node) != null && getRight(node) != null) {
            //有两个子节点的情况
//            RBNode pNode = getSuccessor(node);//找到后继或前驱节点,这里使用后继
            RBNode pNode = getPrecursor(node);//前驱
            //用后继节点的值, 覆盖给删除节点
            node.key = pNode.key;
            node.value = pNode.value;
            //这时要删除的节点就变成了 后继节点, 也就变成了情况2 ,或1了
            node = pNode;
        }
        //找到后继节点的子节点(替代节点)
        RBNode replacement = node.left==null ? node.right:node.left;
        //2, 再情况2, 情况2 可能是情况3 转换来的
        if (replacement != null) { //如果后继节点有子节点说明是情况2
            replacement.parent = node.parent;
            if ( getParent(node) == null ){//说明我们删除的节点是根节点
                root = replacement;
            } else if (getLeft(getParent(node)) == node) { //如果是node父节点的左节点, 就换成replacement
                getParent(node).left = replacement;
            }else { //如果是node父节点的右节点, 就换成replacement
                getParent(node).right = replacement;
            }
            //要删除的node节点全部设置成空 , GC
            node.right = node.parent = node.right = null ;
            if (getColor(node) == BLACK) { //如果删除的节点是红色, 不需要调整
                //做调整操作
                fixAfterRemove(replacement);
            }
        }else if (node.parent == null){ // node 没有父节点说明是root节点
                root = null;
        }else { //就是情况1
            //先调整再删除
            if (node.color == BLACK) {
                fixAfterRemove(node);
            }
            if(node.parent != null){//如果他没有父节点再把指向关系去掉
                if(node == node.parent.left){
                    node.parent.left = null;
                }else{
                    node.parent.right = null;
                }
                node = null;
            }
        }
    }

    /**
     * 删除节点后的调整操作
     * 2-3-4数操作
     *  1. 删除3,4 节点, 自己能搞定
     *  2. 删除2 节点, 自己搞不定, 需要兄弟借, 兄弟借
     *      父亲下来, 兄弟找一个节点替换父亲节点位置
     *  3. 删除2 节点, 自己搞不定, 兄弟不借
     *
     * @param node
     */
    private void fixAfterRemove(RBNode node) {
        // 情况2 和3
        //如果是root节点直接改为黑色就可以了, 替换的节点是红色就不需要调整了
        while (node != root && getColor(node) == BLACK ){
            //判断node是父节点的左节点还是有节点
            if ( node == getLeft(getParent(node))){
                //1. 找到兄弟节点
                RBNode bro = getParent(node).right;
                // 判断找到的是不是真的兄弟节点 ---- 2-3-4 转红黑树3节点有两种情况
                if (getColor(bro) == RED) {
                    //如果是红色, 找到的就不是真的兄弟节点, 需要一次变色加左旋转
                    setColor(bro,BLACK);
                    setColor(getParent(node),RED);
                    leftRotate(getParent(node));
                    bro = getParent(node).right;//找到真兄弟了
                }
                //判断能不能借
                //兄弟节点一个子节点都没有, 不借
                if (getColor(getLeft(bro)) == BLACK && getColor(getRight(bro)) == BLACK) {
                    //2没有子节点, 不借
                    setColor(bro,RED);
                    node = getParent(node);
                }else {
                    //2兄弟借
                    //如果兄弟节点的子节点是左边, 需要先变色, 右旋一次
                    if (getColor(getRight(bro)) == BLACK) {
                        //右侧子节点为空, 那就有左子节点
                        setColor(bro,RED);
                        setColor(getLeft(bro),BLACK);
                        rightRotate(bro);
                        bro = getRight(getParent(node));
                    }
                    //需要根据父节点做一次左旋操作, 变色
                    setColor(bro,getColor(getParent(node)));
                    setColor(getParent(node),BLACK);
                    setColor(getRight(bro),BLACK);
                    leftRotate(getParent(node));
                    node =root; //结束循环, 针对3的处理
                }
            }else {
                //1. 找到兄弟节点
                RBNode bro = getParent(node).left;
                // 判断找到的是不是真的兄弟节点 ---- 2-3-4 转红黑树3节点有两种情况
                if (getColor(bro) == RED) {
                    //如果是红色, 找到的就不是真的兄弟节点, 需要一次变色加左旋转
                    setColor(bro,BLACK);
                    setColor(getParent(node),RED);
                    rightRotate(getParent(node));
                    bro = getParent(node).left;//找到真兄弟了
                }
                //判断能不能借
                //兄弟节点一个子节点都没有, 不借
                if (getColor(getLeft(bro)) == BLACK && getColor(getRight(bro)) == BLACK) {
                    //2没有子节点, 不借
                    setColor(bro,RED);
                    node = getParent(node);
                }else {
                    //2兄弟借
                    //如果兄弟节点的子节点是左边, 需要先变色, 右旋一次
                    if (getColor(getLeft(bro)) == BLACK) {
                        //右侧子节点为空, 那就有左子节点
                        setColor(bro,RED);
                        setColor(getRight(bro),BLACK);
                        leftRotate(bro);
                        bro = getLeft(getParent(node));
                    }
                    //需要根据父节点做一次左旋操作, 变色
                    setColor(bro,getColor(getParent(node)));
                    setColor(getParent(node),BLACK);
                    setColor(getLeft(bro),BLACK);
                    rightRotate(getParent(node));
                    node =root; //结束循环, 针对3的处理
                }
            }
        }



        //1. 替换的节点为红色, 只需要变色为黑色集客
        setColor(node,BLACK);
    }
}

put方法测试

运行结果

image-20220321221819016

网站验证

Red/Black Tree Visualization (usfca.edu)

image-20220321221911413

remove方法测试 (前驱)

初始状态一致

image-20220322144343258
image-20220322144536873

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值