手撕红黑树

首先声明,这是个人看看完 该红黑树教程。掺杂了个人理解。不是面面俱到,所以如果有小伙伴点击进来想学红黑树,我建议先把视频看一遍,然后在看着我的笔记,默写出红黑树。

红黑树的本质

① 所有节点非红即黑
② 根节点必须为黑色
③ 所有的叶子节点都是黑色(NIL节点。多数情况下隐藏)
④ 没有两两连续的红色节点,也就是说红色节点的孩子节点必须是黑色
⑤ 任意一个节点,到叶子节点所经过的黑色节点数目一样多(简称 “黑高”一致)

以上的性质完成对应的2-3-4树(4阶的B - tree)如果不懂 还是建议把视频看完再来

左旋

show

在这里插入图片描述

 private void rotateLeft(RBNode rbNode) {
 		//记录左边节点
        RBNode rNode = rightOfNode(rbNode);
        rbNode.right = null;
        rNode.parent = parentOfNode(rbNode);

        if(rNode.parent != null) {
            RBNode p = rNode.parent;
            if(leftOfNode(p) == rbNode) {
                p.left = rNode;
            }else {
                p.right = rNode;
            }
        }else {
            head = rNode;
        }
        RBNode rlNode = leftOfNode(rNode);
        if(rlNode != null) {
            rbNode.right = rlNode;
            rlNode.parent = rbNode;
        }
        rNode.left = rbNode;
        rbNode.parent = rNode;

    }

右旋

show

在这里插入图片描述

	private void rotateRight(RBNode rbNode) {
        RBNode lNode = leftOfNode(rbNode);
        rbNode.left = null;
        lNode.parent = parentOfNode(rbNode);
        if(lNode.parent != null) {
            RBNode p = lNode.parent;
            if(leftOfNode(p) == rbNode) {
                p.left = lNode;
            }else {
                p.right = lNode;
            }
        }else {
            head = lNode;
        }

        RBNode lrNode = rightOfNode(lNode);
        if(lrNode != null) {
            rbNode.left = lrNode;
            lrNode.parent = rbNode;
        }
        lNode.right = rbNode;
        rbNode.parent = lNode;
    }

插入(我们已知插入节点必须为红色)

① 如果根节点为null, 那么插入节点为根节点,把颜色改成黑色

② 如果插入位置的父亲节点是 黑色 ,那么直接插入。

③ 如果插入位置的父亲节点是 红色,并且叔叔节点也是 红色, 那么把父亲节点和叔叔节点,染黑,把祖父节点 染红。递归处理祖父节点

④ 如果插入位置的父亲节点是 红色, 并且叔叔节点 黑色NIL的情况分一下四种处理方式

  1. LL: 祖父节点变红,父亲节点变黑, 使 祖父 节点 右转
  2. LR:父亲 节点 左转,变成 LL情况
  3. RR: 祖父节点变红,父亲节点变黑, 使 祖父 节点 左转
  4. RL:父亲 节点 右转,变成 RR情况

注意: 在插入的时间,并不会造成情况 ④ 中,父亲节点为 红色,叔叔节点 存在并为黑色 的情况,因为存在这种情况下,“黑高是不一致的”,出现如上情况只有在 ③ 向上递归造成。

删除

① 被删除的节点没有子节点,如果是 红色 直接删除,黑色,先调节后删除

② 被删除的节点只有一个子节点,让子节点接替用来父亲节点的位置,并把颜色变成 黑色。因为如下图的得出的结果


在这里插入图片描述

③ 被删除的节点同时存在左右两个孩子节点

我们可以找到后继节点(大于当前节点的最小值,中序遍历下该节点后一个数),或者前驱节点(小于当前节点的最大值,中序遍历下该节点前一个值)。然后进行替换,在删除该 [前驱 / 后继]节点,该 [前驱 / 后继]节点 必定只存在以下两种情况,没有孩子节点,有一个孩子节点,并且在他的 反方向边。因为如果存在两个孩子,或者在同一个边,那么**[前驱 / 后继]节点**必定就不是该节点。所以可以回到 ① ② 处理

删除黑色节点的处理过程

首先到这里,我们必须保持一个重要的思想,==如何维持黑高?==这个是最为重要的问题,我们可以试着自己画图,通过自己逻辑看看怎么能在删除一个 **黑色节点** 的情况维持下 “黑高”,这其实是一个很有必要的过程。当然是在你熟悉了删除流程。

找到真正的兄弟节点 (如果我们要直接删除5节点,或者是删除4(通过后继节点替换方法,也是删除 5节点))

在这里插入图片描述


如果你看了视频,就会知道我在画什么,通过这个图,我们知道其实 8节点,不是真正 5的兄弟节点,他的兄弟 是 7/7.5的节点。所以我们需要处理一下,找到真正兄弟节点。看左图,我们很容易得出,让 6节点 左旋即可,但是为了维持 黑高,需要让 8节点变成 黑色6节点变成 红色。 如下图


在这里插入图片描述


那么你会说,我不会每次都要画个2-3-4树来判断是不是他的真正兄弟吧,其实不用,真正的兄弟必定是 黑色, 如果是 红色。 那么就要经过处理,这是这是一个方向,相反方向就 反着来就行了


在这里插入图片描述
有没有奇怪,为什么黑色节点必然有兄弟, 不然 “黑高” 不一致 这句话 。因为从父亲角度来看,我有一边孩子 是黑色 黑高 为 1 ,如果我另外一边 没有一个 黑色 节点 或 没有一个 红色 带 两个 黑色 节点 的话。那么我的黑高 肯定不一致。如下图。已删除左下节点为需要调整节点
在这里插入图片描述

左边是不存在的结果,右边是所有存在的结果。不难看出,必定有兄弟。(右下角左后一个图)这里提示一下,为什么左黑只能带有相反侧红色节点,因为如果 同侧也有(相当于他不是真正【前驱/后续节点】)其实就是看你如何处理,反正红色节点 只能存在一边,左右都可以。牢记【前驱/后续节点】的定义

兄弟节点有得借

兄弟有的借的情况,又对应了
在这里插入图片描述

因为非真正兄弟,需要作出处理。然后转变如下图
在这里插入图片描述
想象一下,兄弟节点要借一个节点给你,同时也要保持这树左右两边的“黑高不会”。以上述删除 左下 黑色节点 为例。我们已知 左分支 黑高 - 1, 那么兄弟分支(右分支)如何在借节点的情况下,还保持自己黑高不变的同时,并维持着搜索树性质 我先把数字填上
在这里插入图片描述
如果你能读懂下面这段分析,那么你就会了接下来的操作

我们先不看数字,就看颜色。 左边少了一个 黑色 节点, 兄弟我直接给你一个,然后 黑色 节点。就完事了。 上面三个图,分别能给谁,把 自己孩子节点 染黑 送给对面,就满足了以上的操作。

我们先不看颜色,只看数字。 发现就算少了一个 5. 搜索二叉树的性质没有变。不用做处理

结合两者,我直接把孩子染色给你, 不管给6.5 还是 7.5。 搜素二叉树的性质就会被违背。如下图
在这里插入图片描述
那么结合这种情况,直接给你是不可以的了,这辈子都不可能。所以你需要通过父亲来调解。问问父亲该怎么做。
父亲 6:行吧,你少了一个黑色,我把自己变黑给你好了,这样你这边就不缺了(父爱的伟大)
兄弟 7:爸爸走了,那我去顶替爸爸的位置(长子为大)。他什么颜色我就什么什么。稍等一下,我考虑一下我的继承者。我的位置给谁坐。回到如下图
在这里插入图片描述

兄弟 7 节点要上去 他 左边的儿子 6.5太小了 没办法继承他的皇位(二叉搜索树的原理)。那么只能 7.5 来继承。那么就会存在 那么如上图所示 右边两个是可以直接解决问题的。
流程: 父亲 6 变黑色 下来 ,兄弟 7 替换 (父亲6位置 和 颜色)。 7.5字节(兄弟7 右儿子)变黑 继承 他父亲的位置。 【6.5节点不一定存在】。他呢 完成可以不动 。有她没她 一定的事。看下图。

情况一 兄弟节点存在一个比他大节点

在这里插入图片描述

情况二 兄弟节点两个孩子节点

在这里插入图片描述
【6.5节点】完全可以不动,但是因为减少操作次数,一个左旋操作就完成。就不必要麻烦了。

情况三 兄弟节点存在一个比他小节点(稍微麻烦一点)

在这里插入图片描述

我们又来演戏一下。

6 父亲 : 左孩子(5节点)你要走了, 那我就变成 黑色 代替 你的位置 。。。。
7 兄弟 : 父亲 6 不在位了, 那么我 先给自己找个继承者。再上去。但是发现,没有一个 够格坐他位置的人(没有比他大的节点)。
6.5 兄弟左节点 : 让我来吧,我来继承 父亲6 的 位置。(越权夺位)

按照上面的情景剧,就会变成如下图的结果
在这里插入图片描述
这就是我们最终想到得到的效果图。通过代码,其实有很多东西实现方法。可以不需要按照源码一样转来转去。那么正在的过程是怎么样子的呢。继续看下图
在这里插入图片描述
看到上面的图,看代码理解一下
在这里插入图片描述

兄弟节点没得借

兄弟没有节点给你了,但是你这边分支黑高减 1 了 ,那兄弟我 也把我的黑色节点 变成红色。相当于 我的分支也减1。 然后其他让父亲去处理就好了。相当于 左侧 因为 删减 黑高 -1 , 右侧 因为 变红 黑高 -1.。该子树确实平衡了,那么上面的子树呢?所以需要 把父亲当做需要调节平衡的节点
在这里插入图片描述
在这里插入图片描述

总结

红黑树,在死记硬背的过程当中,一定要理解最为重要的5大性质。在处理节点的过程当中一个要思考,如何处理才能保持住红黑树的平衡,就算我们的代码和别人的代码不一样,只要我们能维持红黑树的平和,那么这就是一棵合情合法合理的红黑树。你们大可不必看我的代码,其实别人的代码,其实也看不懂,一定要脑子里面有那幅图。才能处理好一棵红黑树。又回到一开始,如果想要学习红黑树。请看该红黑树教程

完整代码

	package com.ccn.redblackTree;

/**
 * @Author: CCN
 * @Date: 2021-10-21 11:04
 */
public class RBTree<K extends Comparable<K> , V> {

    private static final boolean RED = true;
    private static final boolean BLACK = false;
    private RBNode<K,V> head = null;

    public RBNode<K, V> getHead() {
        return head;
    }

    public void put(K key , V value) {
        RBNode<K, V> rbNode = new RBNode<>();
        rbNode.setColor(RED);
        rbNode.setKey(key);
        rbNode.setValue(value);

        if (head == null) {
            head = rbNode;
            rbNode.setColor(BLACK);
            return ;
        }
        RBNode p = null;
        RBNode cur = head;
        while(cur != null) {
            p = cur;
            int cmp = cur.key.compareTo(key);
            if(cmp == 0) {
                cur.setValue(value);
                return;
            }else if(cmp > 0) {
                cur = cur.left;
            }else {
                cur = cur.right;
            }
        }

        int cmp = p.key.compareTo(key);
        if(cmp > 0) {
            p.left = rbNode;
        }else {
            p.right = rbNode;
        }
        rbNode.parent = p;
        if(isRed(p)) {
            fixAfterPut(rbNode);
        }
    }
    public V  remove(K key) {
        RBNode rbNode = searchNode(key);
        if(rbNode == null) return null;
        V oldVal = (V) rbNode.value;
        //有两个子节点
        if (rbNode.left != null && rbNode.right != null) {
            //
            RBNode subsequent = subsequent(rbNode);
            rbNode.key = subsequent.key;
            rbNode.value = subsequent.value;
            rbNode = subsequent;
        }
        RBNode replacement = rbNode.left == null ? rbNode.right : rbNode.left;
        //有一个子节点
        if(replacement != null) {
                //有一个子节点,那么删除节点必定是黑色,直接删除,把替换节点改一下颜色
                RBNode parent = parentOfNode(rbNode);
                if (parent == null) {
                    head = replacement;
                }
                else if(leftOfNode(parent) == rbNode) {
                    parent.left = replacement;
                }else {
                    parent.right = replacement;
                }
                replacement.parent = parent;
                rbNode.parent = rbNode.left = rbNode.right = null;
                if (!isRed(rbNode)) {
                    fixAfterRemove(replacement);
                }
        }
        //没有子节点,但是是删除根节点
        else if (rbNode == head){
            head = null;
        }
        //没有子节点
        else {
            if(!isRed(rbNode)) {
                fixAfterRemove(rbNode);
            }
            RBNode parent = parentOfNode(rbNode);
            if(leftOfNode(parent) == rbNode) {
                parent.left = null;
            }else {
                parent.right = null;
            }
            rbNode.parent = null;
        }

        return oldVal;
    }

    private void fixAfterRemove(RBNode rbNode) {
        while(rbNode != head && !isRed(rbNode)) {
            //找到真正的兄弟
            RBNode parent = parentOfNode(rbNode);
            //黑色节点必然有兄弟,不然黑高不一致
            RBNode brother = parent.left == rbNode ? parent.right : parent.left;
            if (isRed(brother)) {
                setColor(parent, RED);
                setColor(brother, BLACK);
                if(parent.left == brother) {
                    rotateLeft(parent);
                }else {
                    rotateRight(parent);
                }
                parent = parentOfNode(rbNode);
                brother = parent.left == rbNode ? parent.right : parent.left;
            }

            //兄弟没得借
            if(brother.left == null && brother.right == null) {
                //也就是兄弟也是一个人。因为删除节点是黑色,那么真正的兄弟节点必定也是黑色。让他变成红色,维持左右两边黑高
                setColor(brother, RED);
                //但是为了维持整个分支的黑高,需要找到一个最先为红色根节点,让他变成黑色/或者进行其他的平衡处理。
                rbNode = parentOfNode(rbNode);
            }
            //兄弟有的借
            else {
                if (parent.right == brother) {
                    //对应234树 3节点 且 上黑 左下红的情况。特殊处理
                    if(brother.right == null) {
                        //因为 只有一个左孩子,如果借那么就全部都给了。要右转保留一个
                        setColor(brother, RED);
                        setColor(brother.left, BLACK);
                        rotateRight(brother);
                        //因为兄弟节点转动了,改变了真正兄弟节点的位置。重新找到兄弟节点
                        brother = parentOfNode(brother);
                    }
                    parent = parentOfNode(rbNode);
                    setColor(brother, parent.color);
                    setColor(brother.right, BLACK);
                    setColor(parent, BLACK);
                    rotateLeft(parent);
                   // rbNode = head 也等价于 break, 下一轮不做了
                    break;
                }
                else {
                    //情况三
                    if(brother.left == null) {
                        //因为 只有一个左孩子,如果借那么就全部都给了。要右转保留一个
                        setColor(brother, RED);
                        setColor(brother.right, BLACK);
                        rotateLeft(brother);
                        //因为兄弟节点转动了,改变了真正兄弟节点的位置。重新找到兄弟节点
                        brother = parentOfNode(brother);
                    }
                    //情况一
                    parent = parentOfNode(rbNode);
                    setColor(brother, parent.color);
                    setColor(brother.left, BLACK);
                    setColor(parent, BLACK);
                    rotateLeft(parent);
                    // rbNode = head 也等价于 break, 下一轮不做了
                    break;
                }
            }
        }
        setColor(rbNode, BLACK);
    }

    //找到前驱节点,小于当前节点最大值(中序遍历下,前一个元素)
    private RBNode precursor(RBNode rbNode) {
        RBNode rNode = rbNode.left;
        //不存在右子节点,向上找
        if(rNode == null) {
            RBNode parent;
            RBNode gParent;
            do {
                parent = parentOfNode(rbNode);
                gParent = parentOfNode(parent);
            }while (gParent != null && gParent.right != parent);
            return gParent;
        }
        //存在右子节点,找右边树最左的树
        else {
            RBNode p = rbNode;
            while(rNode != null) {
                p = rNode;
                rNode = rNode.right;
            }
            return p;
        }
    }

    //找到后续节点,大于当前节点最小值(中序遍历下,后一个元素)
    private RBNode subsequent(RBNode rbNode) {
        RBNode rNode = rbNode.right;
        //不存在右子节点,向上找
        if(rNode == null) {
            RBNode parent;
            RBNode gParent;
            do {
                parent = parentOfNode(rbNode);
                gParent = parentOfNode(parent);
            }while (gParent != null && gParent.left != parent);
            return gParent;
         }
        //存在右子节点,找右边树最左的树
        else {
            RBNode p = rbNode;
            while(rNode != null) {
                p = rNode;
                rNode = rNode.left;
            }
            return p;
        }
    }
    private void fixAfterPut(RBNode<K,V> rbNode) {
        this.head.color = BLACK;
        RBNode parent = parentOfNode(rbNode);
        if(!isRed(parent)) return ;
        RBNode gParent = parentOfNode(parent);
        RBNode uncle = uncleOfNode(rbNode);
        // 处理 父叔双红
        if(isRed(parent) && isRed(uncle)) {
            setColor(uncle, BLACK);
            setColor(parent, BLACK);
            // 父叔双红 一定要祖父节点。毕竟根节点为黑色
            setColor(gParent, RED);
            fixAfterPut(parentOfNode(parent));
            return;
        }
        // 处理 LL LR
        if(gParent.left == parent) {
            // LR特殊处理
            if(parent.right == rbNode) {
                rotateLeft(parent);
                fixAfterPut(parent);
                return;
            }
            setColor(gParent, RED);
            setColor(parent, BLACK);
            setColor(rbNode, RED);
            rotateRight(gParent);

        }
        // 处理 RR RL
        else {
            // RL
            if(parent.left == rbNode) {
                rotateRight(parent);
                fixAfterPut(parent);
                return;
            }
            setColor(gParent, RED);
            setColor(parent, BLACK);
            setColor(rbNode, RED);
            rotateLeft(gParent);

        }
    }



    private boolean isRed(RBNode rbNode) {
        return rbNode == null ? BLACK : rbNode.color == RED;
    }

    private RBNode leftOfNode(RBNode rbNode) {
        return rbNode.left;
    }

    private RBNode rightOfNode(RBNode rbNode) {
        return rbNode.right;
    }

    private void setColor(RBNode rbNode, boolean color) {
        if(rbNode == null) return;
        rbNode.setColor(color);
    }

    private RBNode parentOfNode(RBNode rbNode) {
        return rbNode.parent;
    }

    private RBNode uncleOfNode(RBNode rbNode) {
        RBNode pNode = parentOfNode(rbNode);
        RBNode gNode = parentOfNode(pNode);
        if (gNode == null) return null;
        if(leftOfNode(gNode) == pNode) return gNode.right;
        return gNode.left;
    }

    private RBNode searchNode(K k) {
        RBNode cur = head;
        while(cur != null) {
            int cmp = cur.key.compareTo(k);
            if(cmp == 0) return cur;
            else if(cmp > 0) cur = cur.left;
            else cur = cur.right;
        }
        return cur;
    }

    private void rotateLeft(RBNode rbNode) {
        RBNode rNode = rightOfNode(rbNode);
        rbNode.right = null;
        rNode.parent = parentOfNode(rbNode);

        if(rNode.parent != null) {
            RBNode p = rNode.parent;
            if(leftOfNode(p) == rbNode) {
                p.left = rNode;
            }else {
                p.right = rNode;
            }
        }else {
            head = rNode;
        }
        RBNode rlNode = leftOfNode(rNode);
        if(rlNode != null) {
            rbNode.right = rlNode;
            rlNode.parent = rbNode;
        }
        rNode.left = rbNode;
        rbNode.parent = rNode;

    }

    private void rotateRight(RBNode rbNode) {
        RBNode lNode = leftOfNode(rbNode);
        rbNode.left = null;
        lNode.parent = parentOfNode(rbNode);
        if(lNode.parent != null) {
            RBNode p = lNode.parent;
            if(leftOfNode(p) == rbNode) {
                p.left = lNode;
            }else {
                p.right = lNode;
            }
        }else {
            head = lNode;
        }

        RBNode lrNode = rightOfNode(lNode);
        if(lrNode != null) {
            rbNode.left = lrNode;
            lrNode.parent = rbNode;
        }
        lNode.right = rbNode;
        rbNode.parent = lNode;
    }



    public static class RBNode<K extends Comparable<K>, V> {

        private K key;
        private V value;
        private RBNode parent;
        private RBNode left;
        private RBNode right;
        private boolean color;

        public RBNode() {
        }

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

        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 getColor() {
            return color;
        }

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

测试代码

	/**
 * @author Jerssy
 * @version V1.0
 * @Description
 * @create 2020-11-15 22:12
 */
public class TreeOperation<T> {


    private final HashMap<String, Method> map= new HashMap<>();

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


    // 用于获得树的层数
    public   int getTreeDepth(T root) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        if (root == null){
            return 0;
        }


        return  (1 + Math.max(getTreeDepth(getTreeFields(root,"left")), getTreeDepth(getTreeFields(root,"right"))));
    }


    private void writeArray(T currNode, int rowIndex, int columnIndex, String[][] res, int treeDepth,int arrayWidth) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {


        // 保证输入的树不为空
        if (currNode == null) return;
        String resNodeValue;

        T key = getTreeFields(currNode, "key");
        T value = getTreeFields(currNode, "value");
        T color=getTreeFields(currNode, "color");


        if (value!=null) {
            resNodeValue=color!=null? ((Boolean) color ?"R-"+value:"B-"+value):value+"";
        }
        else if (key!=null) {
            resNodeValue=color!=null? ((Boolean) color ? "\033[31;4m" + " " + key +" " + "\033[0m" : ""+ key) : key+ "";
        }

        else {
            System.out.println("key/value"+"不能都为空!");
            return;
        }
        res[rowIndex][columnIndex] = resNodeValue;

        // 计算当前位于树的第几层
        int currLevel = ((rowIndex + 1) / 2);
        // 若到了最后一层,则返回
        if (currLevel == treeDepth) return;
        // 计算当前行到下一行,每个元素之间的间隔(下一行的列索引与当前元素的列索引之间的间隔)
        int gap = treeDepth - currLevel - 1;

        // 对左儿子进行判断,若有左儿子,则记录相应的"/"与左儿子的值
        T left = getTreeFields(currNode, "left");
        if (left != null) {
            int columnI = Math.max(columnIndex - gap - resNodeValue.length()/2,0);
            res[rowIndex + 1][columnI] = "/";
            writeArray(left, rowIndex + 2, Math.max(columnI-gap,0), res, treeDepth,arrayWidth);
        }

        // 对右儿子进行判断,若有右儿子,则记录相应的"\"与右儿子的值
        T right = getTreeFields(currNode, "right");
        if (right != null) {
            int columnI = Math.min(columnIndex + gap +resNodeValue.length()/2,arrayWidth-1);
            res[rowIndex + 1][columnI] = "\\";
            writeArray(right, rowIndex + 2, Math.min(columnI+gap,arrayWidth-1) , res, treeDepth,arrayWidth);
        }
    }


    public void show(T root)   {
        if (root == null){
            System.out.println("EMPTY!");
            return;
        }
        System.out.println();
        // 得到树的深度
        int treeDepth = 0;
        try {
            //通过反射获取泛型类的属性和方法
            Class<?> treeClass = root.getClass();
            Field[] fields = treeClass.getDeclaredFields();
            Method[] declaredMethods = treeClass.getDeclaredMethods();

            for (Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();
                char[] cs=name.toCharArray();
                cs[0]-=32;

                for (Method method : declaredMethods) {
                    method.setAccessible(true);
                    if (method.getName().equals("get" + String.valueOf(cs))) {
                        Method declaredMethod = treeClass.getDeclaredMethod("get" + String.valueOf(cs));
                        declaredMethod.setAccessible(true);
                        map.put(name, declaredMethod);
                    }
                }

            }
            treeDepth = getTreeDepth(root);

        } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }


        // 最后一行的宽度为2的(n - 1)次方乘3,再加1
        // 作为整个二维数组的宽度
        int arrayHeight = treeDepth * 2 - 1;
        int arrayWidth = (2 << (treeDepth - 2)) * 3 + 1;

        int grepWidth=arrayWidth/treeDepth;
        // 用一个字符串数组来存储每个位置应显示的元素
        String[][] res = new String[arrayHeight][arrayWidth+grepWidth];
        // 对数组进行初始化,默认为一个空格

        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');
        try {
            writeArray(root, 0, arrayWidth / 2, res, treeDepth,arrayWidth+grepWidth);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }

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

    private T getTreeFields(T node,String name) throws InvocationTargetException, IllegalAccessException {

        if (map.containsKey(name)){

            return (T) map.get(name).invoke(node);
        }

        return null;
    }

}

	public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int idx = 0;
        RBTree<Integer, String> redBlackTree = new RBTree<>();
        TreeOperation<RBTree.RBNode> treeOperation = new TreeOperation<>();
        System.out.println("构建开始");
        while (scanner.hasNextLine()) {
            String s = scanner.nextLine();
            if ("end".equals(s)) break;
            redBlackTree.put(Integer.parseInt(s), null);
            treeOperation.show(redBlackTree.getHead());
        }
        System.out.println("构建结束");
        System.out.println("删除开始");
        while (scanner.hasNextLine()) {
            String s = scanner.nextLine();
            redBlackTree.remove(Integer.parseInt(s));
            treeOperation.show(redBlackTree.getHead());
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值