慌了,面试官问了我红黑树,菜虫来啃红黑树了

TreeMap

首先给个网站,自己手动增加和删除红黑树节点网站

BST

说红黑树先从BST二叉查找树进行说起

二叉树:每个子节点只有两个节点的树
二叉查找树(二叉搜索树):
	就是一颗二叉树,他的左节点比父节点要小,
	右节点比父节点要大。他的高度决定的查找效率。

在这里插入图片描述

BST操作
查找(红黑树通用):查找每个节点我们从根节点开始查找
	查找值比当前值大,则搜索右子树
	查找值等于当前值,停止查找,返回当前节点
	查找值比当前值小,则搜索左子树
插入:
要插入节点,必须先找到插入节点位置。
依然是从根节点开始比较,小于根节点的话就和左子树
比较,反之与右子树比较,直到左子树为空或者右子树为空,
则插入到相应为空的位置。
遍历(红黑树通用):
根据一定顺序来访问整个树,
常见的有前序遍历,中序遍历(用的较多),后序遍历

前序遍历:根节点-》左子树-》右子树 
中序遍历:左子树-》根节点-》右子树 
后续遍历:左子树-》右子树-》根节点 
查找最小值(红黑树通用):
沿着根节点的左子树一路查找,直到最后一个不为空的节点,
该节点就是当前这个树的最小节点

查找最大值(红黑树通用):
沿着根节点的右子树一路查找,直到最后一个不为空的节点,
该节点就是当前这个树的最大节点

查找前驱节点(红黑树通用):小于当前节点的最大值
查找后继节点(红黑树通用):大于当前节点的最小值
删除:
本质上是找前驱或者后继节点来替代
叶子节点直接删除(没有前驱或后继节点)
只有一个子节点的用子节点替代
(本质上就是找的前驱节点或者是后继节点,
左节点就是前驱节点,右节点就是后继节点)
有两个子节点的,需要找到替代节点(替代节点就是前驱节点或者后继节点)
删除操作和红黑树一样,只不过红黑树多了着色和旋转过程
BST的问题
BST存在的问题是,树在插入的时候会导致倾斜,
不同的插入顺序会导致数的高度不一样,而树的高度
直接影响了树的查找效率。
最坏的情况所有的节点都在一条斜线上,这样树的高度为N。
基于BST存在的问题,平衡查找二叉树(Balanced BST)产生了。
平衡树的插入和删除的时候,会通过旋转操作将高度保持在LogN。
其中两款具有代表性的平衡术分别为AVL树(高度平衡树,具备二叉搜索
树的全部特性,而且左右子树高度差不超过1)和红黑树。
面试题:有了AVL树为什么还要红黑树呢??
AVL树由于实现比较复杂,而且插入和删除性能差,在实际环境下的应用不如红黑树。
红黑树的实际应用非常广泛,
如Java中的HashMap和TreeSet,Java 8中HashMap的实现因为用
RBTree代替链表(链表长度>8时),性能有所提升。

2-3-4树

说完BST,还要说一下2-3-4,因为红黑树和它两个关系渊源
2-3-4树是四阶的 B树(Balance Tree),
他属于一种多路查找树,它的结构有以下限制:

所有叶子节点都拥有相同的深度。(因为所有节点都是从叶节点进行插入的)

节点只能是 2-节点、3-节点、4-节点之一。
	2-节点:包含 1 个元素的节点,有 2 个子节点;
	3-节点:包含 2 个元素的节点,有 3 个子节点;
	4-节点:包含 3 个元素的节点,有 4 个子节点;
	所有节点必须至少包含1个元素

元素始终保持排序顺序,整体上保持二叉查找树的性质,
即父结点大于左子结点,小于右子结点;
而且结点有多个元素时,每个元素必须大于它左边的和它的左子树中元素。

在这里插入图片描述

2-3-4树的查询操作像普通的二叉搜索树一样,非常简单,
但由于其结点元素数不确定,在一些编程语言中实现起来并不方便,
实现一般使用它的等同——红黑树。

2-3-4树和红黑树对应起来

2-3-4树的每一个结点都对应红黑树的一种结构,
所以每一棵 2-3-4树也都对应一棵红黑树,
下图是 2-3-4树不同结点与红黑树子树的对应。

在这里插入图片描述

插入操作
2-3-4树中结点添加需要遵守以下规则:
	插入都是向最下面一层插入;
	升元:将插入结点由 2-结点升级成 3-结点,或由 3-结点升级成 4-结点;
	向 4-结点插入元素后,需要将中间元素提到父结点升元,原结点变成两个 2-结点,再把元素插入
	2-结点中,如果父结点也是 4-结点,则递归向上层升元,至到根结点后将树高加1;

而将这些规则对应到红黑树里,就是:
	新插入的结点颜色为 红色 ,这样才可能不会对红黑树的高度产生影响。
	2-结点对应红黑树中的单个黑色结点,插入时直接成功(对应 2-结点升元)。
	3-结点对应红黑树中的 黑+红 子树,插入后将其修复成 红++红 子树(对应 3-结点升元);
	4-结点对应红黑树中的 红++红 子树,插入后将其修复成 红色祖父+黑色父叔+红色孩子 子树,然后
	再把祖父结点当成新插入的红色结点递归向上层修复,直至修复成功或遇到 root 结点;

红黑树

红黑树是一种结点带有颜色属性的二叉查找树,
但它在二叉查找树之外,还有以下5大性质:
	1. 节点是红色或黑色。
	2. 根是黑色。
	3. 所有叶子都是黑色(叶子是NIL节点)。
	4. 每个红色节点必须有两个黑色的子节点。
		(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
	5. 从任一节点到其每个叶子的所有简单路径
		都包含相同数目的黑色节点(黑色平衡)。

这些性质都可以从2-3-4树和红黑树的等价关系里面递推过来
比如性质一就是2-3-4树只有三种节点的树,
	对应的等价关系的红黑树的节点要么红要么黑

性质二也是2-3-4树的三种节点对应的红黑树的根节点都是黑色的

性质三,没什么说的,源代码如此

性质四,从对应关系来说,因为对应的都是上黑下红,所以红节点下面
	对应的肯定是黑色,因为无论怎么等价,黑色都是在上面,
	还有因为性质三,叶节点也是黑色的,所以就算最后一个是红色节点
	他的两个孩子是无的,但是默认两个没有的孩子是黑色的
操作
变色:节点的颜色由黑变红或者由红变黑

左旋:以某个节点作为旋转点,其右子节点变为旋转节点的父节点,
右子节点的左子节点变为旋转节点的右子节点,左子节点保持不变。

右旋:以某个节点作为旋转点,其左子节点变为旋转节点的父节点,
左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变。
新增
分情况讨论,主要是要找到插入位置,
然后自平衡(左旋或者右旋)且插入节点是红色
(如果是黑色的话,那么当前分支上就会多出一个黑色节点出来,
从而破坏了黑色平衡),以下分析全部以左子树为例子,右子树的情况则相反。

	如果插入的是第一个节点(根节点),红色变黑色
	如果父节点为黑色,则直接插入,不需要变色
	如果父节点为红色,叔叔节点也是红色(此种情况爷爷节点一定是黑色),
		则父节点和叔叔节点变黑色,爷爷节点变红色(如果爷爷节点是根节点,
		则再变成黑色),爷爷节点此时需要递归
		(把爷爷节点当做新插入的节点再次进行比较)
	如果父节点是红色,没有叔叔节点或者叔叔节点是黑色
		(此时只能是NIL节点),则以爷爷节点为支点右旋,
		旋转之后原来的爷爷节点变红色,原来的父节点变黑色。

在这里插入图片描述

在这里插入图片描述

删除
总结来说:
自己能搞定的自己搞定;搞不定的找兄弟和父亲帮忙;
父亲和兄弟都帮不了那有福同享,有难同当(父亲和兄弟自损)

自己能搞定的自己搞定
如果删除的节点对应于2-3-4树的3节点或者4节点,则直接删除,
不用跟兄弟和父亲借. 如果删除的是红色节点,则直接删;
如果删除的是黑色节点,则红色节点上来替代,变黑即可

搞不定的找兄弟和父亲帮忙
前提是找到“真正“的兄弟节点
兄弟节点有的借(此时兄弟节点一定是黑色,
如果是红色那说明这个节点不是真正的兄弟节点,需要回到上一步找真正的兄弟节点)

	兄弟节点有两个子节点的情况(2个子节点肯定是红色,
	如果是黑色的话相当于此时兄弟节点对应2-3-4树是2节点,
	不可能有多余的元素可以借),此时需要旋转变色
	
	兄弟节点只有一个子节点的情况,此时需要旋转变色
	
兄弟和父亲节点帮不了忙,于是开始递归自损
前提是找到“真正”的兄弟节点
兄弟节点没有多余的元素可借(此时兄弟节点一定为黑色2节点),
此时兄弟节点所在分支也要自损一个黑色节点以此达到黑色平衡,
最快的方式就是兄弟节点直接变红(相当于就是减少一个黑色节点),
此时一父节点为root的子树又达到了平衡(两边都比之前少一个黑色)。
但是以祖父节点为root的树依然是不平衡的,此时需要递归处理。
删除操作:
1、删除叶子节点,直接删除
2、删除的节点有一个子节点,那么用子节点来替代
3、如果删除的节点有2个子节点,此时需要找到前驱节点或者后继节点来替代

删除节点方案:
1、找到前驱节点,复制前驱节点值覆盖预备删除的节点的值,然后删除前驱节点
2、找到后继节点,复制后继节点的值覆盖预备删除的节点的值,然后删除后继节点

被删除的前驱节点或者后继节点只有2种情况:
1、被删节点是叶子节点
2、被删节点只有一个孩子
//情况一、替代节点是红色,则直接染红,
//补偿删除的黑色节点,这样红黑树依然保持平衡
 setColor(x,BLACK);

在这里插入图片描述

//x是左孩子的情况
if (x == leftOf(parentOf(x)))
{
    //兄弟节点
    RBNode rnode = rightOf(parentOf(x));

    //判断此时兄弟节点是否是真正的兄弟节点
    if (colorOf(rnode) == RED)
    {
        setColor(rnode, BLACK);
        setColor(parentOf(x), RED);
        leftRotate(parentOf(x));
        //找到真正的兄弟节点
        rnode = rightOf(parentOf(x));
    }
    //情况三,找兄弟借,兄弟没得借
    if (colorOf(leftOf(rnode)) == BLACK && colorOf(rightOf(rnode)) == BLACK)
    {
        //情况复杂
        setColor(rnode, RED);
        x = parentOf(x);
    }
    //情况二,找兄弟借,兄弟有的借
    else
    {
        //分2种小情况:兄弟节点本来是3节点或者是4节点的情况
        if (colorOf(rightOf(rnode)) == BLACK)
        {
            setColor(leftOf(rnode), BLACK);
            setColor(rnode, RED);
            rightRotate(rnode);
            rnode = rightOf(parentOf(x));
        }
        setColor(rnode, colorOf(parentOf(x)));
        setColor(parentOf(x), BLACK);
        setColor(rightOf(rnode), BLACK);
        leftRotate(parentOf(x));
        x = root;
    }
}

在这里插入图片描述

在这里插入图片描述

代码

package com.jane.redBlackTree;

public class RBTree<K extends Comparable<K>, V>
{
    private static final boolean RED = false;
    private static final boolean BLACK = true;

    private RBNode root;

    public RBNode getRoot()
    {
        return root;
    }

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

    /**
     * 围绕p左旋
     *       pf                    pf
     *      /                     /
     *     p                     pr(r)
     *    / \          ==>      / \
     *  pl  pr(r)              p   rr
     *     / \                / \
     *    rl  rr             pl  rl
     *
     * @param p
     */
    private void leftRotate(RBNode p)
    {
        if (p != null)
        {
            RBNode r = p.right;
            p.right = r.left;
            if (r.left != null)
            {
                r.left.parent = p;
            }
            r.parent = p.parent;
            if (p.parent == null)
            {
                root = r;
            } else if (p.parent.left == p)
            {
                p.parent.left = r;
            } else
            {
                p.parent.right = r;
            }
            r.left = p;
            p.parent = r;
        }
    }

    /**
     * 右旋
     *    pf                pf
     *     \                 \
     *      p             (l)pl
     *     / \      =>      /  \
     *(l)pl  pr            ll   p
     *   / \                   / \
     *  ll lr                 lr  pr
     *
     * @param p
     */
    private void rightRotate(RBNode p)
    {
        if (p != null)
        {
            RBNode l = p.left;
            p.left = l.right;
            if (l.right != null)
            {
                l.right.parent = p;
            }
            l.parent = p.parent;
            if (p.parent == null)
            {
                root = l;
            } else if (p.parent.right == p)
            {
                p.parent.right = l;
            } else
            {
                p.parent.left = l;
            }
            l.right = p;
            p.parent = l;
        }
    }

    /**
     * 找到指定节点的前驱节点,即找小于node节点的最大值
     * @param node
     */
    private RBNode predecessor(RBNode node)
    {
        if (node == null)
        {
            return null;
        } else if (node.left != null)
        {
            RBNode p = node.left;
            while (p.right != null)
            {
                p = p.right;
            }
            return p;
        }
        /**
         * 这种情况在删除节点的时候是不会遇到的,但是我们需要写完整的找前驱节点
         * 这个就是当前节点没有子节点的情况,所以就一直向父节点来找
         * 因为当前节点一直是父节点的左孩子,所以当当前节点是父节点的右孩子时
         * 就终止寻找,这个父节点就是要找的节点
         */
        else
        {
            RBNode p = node.parent;
            RBNode ch = node;
            while (p != null && ch == p.left)
            {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

    /**
     * 找后继节点,即大于节点的最小值
     * @param node
     * @return
     */
    private RBNode successor(RBNode node)
    {
        if (node == null)
        {
            return null;
        } else if (node.right != null)
        {
            RBNode p = node.right;
            while (p.left != null)
            {
                p = p.left;
            }
            return p;
        } else
        {
            RBNode p = node.parent;
            RBNode ch = node;
            while (p != null && ch == p.right)
            {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

    private boolean colorOf(RBNode node)
    {
        return node == null ? BLACK : node.color;
    }

    private RBNode parentOf(RBNode node)
    {
        return node != null ? node.parent : null;
    }

    private RBNode leftOf(RBNode node)
    {
        return node != null ? node.left : null;
    }

    private RBNode rightOf(RBNode node)
    {
        return node != null ? node.right : null;
    }

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

    public void put(K key, V value)
    {
        RBNode t = this.root;
        //如果是根节点
        if (t == null)
        {
            root = new RBNode<>(key, value == null ? key : value, null);
            return;
        }
        int cmp;
        //寻找插入位置
        //定义一个双亲指针
        RBNode parent;
        if (key == null)
        {
            throw new NullPointerException();
        }
        //沿着跟节点寻找插入位置
        do
        {
            parent = t;
            cmp = key.compareTo((K) t.key);
            if (cmp < 0)
            {
                t = t.left;
            } else if (cmp > 0)
            {
                t = t.right;
            } else
            {
                t.setValue(value == null ? key : value);
                return;
            }
        } while (t != null);

        RBNode<K, Object> e = new RBNode<>(key, value == null ? key : value, parent);
        //如果比较最终落在左子树,则直接将父节点左指针指向e
        if (cmp < 0)
        {
            parent.left = e;
        }
        //如果比较最终落在右子树,则直接将父节点右指针指向e
        else
        {
            parent.right = e;
        }
        //调整
        fixAfterPut(e);
    }

    /**
     * 1、2-3-4树:新增元素+2节点合并(节点中只有1个元素)=3节点(节点中有2个元素)
     *    红黑树:新增一个红色节点+黑色父亲节点=上黑下红(2节点)--------------------不要调整
     *
     * 2、2-3-4树:新增元素+3节点合并(节点中有2个元素)=4节点(节点中有3个元素)
     *    这里有4种小情况(左3,右3,还有2个左中右不需要调整)------左3,右3需要调整,其余2个不需要调整
     *    红黑树:新增红色节点+上黑下红=排序后中间节点是黑色,两边节点都是红色(3节点)
     *
     * 3、2-3-4树:新增一个元素+4节点合并=原来的4节点分裂,中间元素升级为父节点,新增元素与剩下的其中一个合并
     *    红黑树:新增红色节点+爷爷节点黑,父节点和叔叔节点都是红色=爷爷节点变红,父亲和叔叔变黑,如果爷爷是根节点,则再变黑
     *
     *
     * @param x
     */
    private void fixAfterPut(RBNode x) {
        x.color = RED;
        //本质上就是父节点是黑色就不需要调整,对应情况就是2,3
        while (x != null && x != root && x.parent.color == RED)
        {
            //1、x的父节点是爷爷的左孩子(左3)
            if (parentOf(x) == leftOf(parentOf(parentOf(x))))
            {
                //叔叔节点
                RBNode y = rightOf(parentOf(parentOf(x)));
                //第3种情况
                if (colorOf(y) == RED)
                {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    //爷爷节点递归
                    x = parentOf(parentOf(x));
                }
                //第2种情况
                else
                {
                    if (x == rightOf(parentOf(x)))
                    {
                        x = parentOf(x);
                        leftRotate(x);
                    }
                    //父亲变黑
                    setColor(parentOf(x), BLACK);
                    //爷爷变红
                    setColor(parentOf(parentOf(x)), RED);
                    //根据爷爷节点右旋转
                    rightRotate(parentOf(parentOf(x)));
                }
            }
            //2、跟第一种情况相反操作
            else
            {
                //右3
                //叔叔节点
                RBNode y = leftOf(parentOf(parentOf(x)));
                //第3种情况
                if (colorOf(y) == RED)
                {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    //爷爷节点递归
                    x = parentOf(parentOf(x));
                }
                //第2种情况
                else
                {
                    if (x == leftOf(parentOf(x)))
                    {
                        x = parentOf(x);
                        rightRotate(x);
                    }
                    //父亲变黑
                    setColor(parentOf(x), BLACK);
                    //爷爷变红
                    setColor(parentOf(parentOf(x)), RED);
                    //根据爷爷节点右旋转
                    leftRotate(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }

    public V remove(K key)
    {
        RBNode node = getNode(key);
        if (node == null)
        {
            return null;
        }
        V oldValue = (V) node.value;
        deleteNode(node);
        return oldValue;
    }

    /**
     * 删除操作:
     * 1、删除叶子节点,直接删除
     * 2、删除的节点有一个子节点,那么用子节点来替代
     * 3、如果删除的节点有2个子节点,此时需要找到前驱节点或者后继节点来替代
     * @param node
     */
    private void deleteNode(RBNode node)
    {
        //3、node节点有2个孩子
        if (node.left != null && node.right != null)
        {

            //后继节点替代
            RBNode rep = successor(node);
            //前驱节点替代
//            RBNode rep= predecessor(node);
            node.key = rep.key;
            node.value = rep.value;
            node = rep;
        }

        RBNode replacement = node.left != null ? node.left : node.right;
        //2、替代节点不为空
        if (replacement != null)
        {
            //替代者的父指针指向的原来node的父亲
            replacement.parent = node.parent;
            //node是根节点
            if (node.parent == null)
            {
                root = replacement;
            }
            //node是左孩子,所以替代者依然是左孩子
            else if (node == node.parent.left)
            {
                node.parent.left = replacement;
            }
            //node是右孩子,所以替代者依然是右孩子
            else
            {
                node.parent.right = replacement;
            }
            //将node的左右孩子指针和父指针都指向null(此时node处于游离状态,等待垃圾回收)
            node.left = node.right = node.parent = null;

            //替换完之后需要调整平衡
            if (node.color == BLACK)
            {
                //需要调整,这种情况一定是红色(替代节点一定是红色,此时只要变色)
                fixAfterRemove(replacement);
            }
        }
        //删除节点就是根节点
        else if (node.parent == null)
        {
            root = null;
        }
        //1、node节点是叶子节点,replacement为null
        else
        {
            //先调整
            if (node.color == BLACK)
            {
                fixAfterRemove(node);
            }
            //再删除
            if (node.parent != null)
            {
                if (node == node.parent.left)
                {
                    node.parent.left = null;
                } else if (node == node.parent.right)
                {
                    node.parent.right = null;
                }
                node.parent = null;
            }
        }
    }

    /**
     * 删除后调整
     * @param x
     */
    private void fixAfterRemove(RBNode x)
    {
        while (x != root && colorOf(x) == BLACK)
        {
            //x是左孩子的情况
            if (x == leftOf(parentOf(x)))
            {
                //兄弟节点
                RBNode rnode = rightOf(parentOf(x));

                //判断此时兄弟节点是否是真正的兄弟节点
                if (colorOf(rnode) == RED)
                {
                    setColor(rnode, BLACK);
                    setColor(parentOf(x), RED);
                    leftRotate(parentOf(x));
                    //找到真正的兄弟节点
                    rnode = rightOf(parentOf(x));
                }
                //情况三,找兄弟借,兄弟没得借
                if (colorOf(leftOf(rnode)) == BLACK && colorOf(rightOf(rnode)) == BLACK)
                {
                    //情况复杂
                    setColor(rnode, RED);
                    x = parentOf(x);
                }
                //情况二,找兄弟借,兄弟有的借
                else
                {
                    //分2种小情况:兄弟节点本来是3节点或者是4节点的情况
                    if (colorOf(rightOf(rnode)) == BLACK)
                    {
                        setColor(leftOf(rnode), BLACK);
                        setColor(rnode, RED);
                        rightRotate(rnode);
                        rnode = rightOf(parentOf(x));
                    }
                    setColor(rnode, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(rnode), BLACK);
                    leftRotate(parentOf(x));
                    x = root;
                }
            }
            //x是右孩子的情况
            else
            {

                //兄弟节点
                RBNode rnode = leftOf(parentOf(x));
                //判断此时兄弟节点是否是真正的兄弟节点
                if (colorOf(rnode) == RED)
                {
                    setColor(rnode, BLACK);
                    setColor(parentOf(x), RED);
                    rightRotate(parentOf(x));
                    //找到真正的兄弟节点
                    rnode = leftOf(parentOf(x));
                }
                //情况三,找兄弟借,兄弟没得借
                if (colorOf(rightOf(rnode)) == BLACK && colorOf(leftOf(rnode)) == BLACK)
                {
                    //情况复杂
                    setColor(rnode, RED);
                    x = parentOf(x);
                }
                //情况二,找兄弟借,兄弟有的借
                else
                {
                    //分2种小情况:兄弟节点本来是3节点或者是4节点的情况
                    if (colorOf(leftOf(rnode)) == BLACK)
                    {
                        setColor(rightOf(rnode), BLACK);
                        setColor(rnode, RED);
                        leftRotate(rnode);
                        rnode = leftOf(parentOf(x));
                    }
                    setColor(rnode, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(leftOf(rnode), BLACK);
                    rightRotate(parentOf(x));
                    x = root;
                }
            }
        }
        //情况一、替代节点是红色,则直接染黑,补偿删除的黑色节点,这样红黑树依然保持平衡
        setColor(x, BLACK);
    }

    private RBNode getNode(K key)
    {
        RBNode node = this.root;
        while (node != null)
        {
            int cmp = key.compareTo((K) node.key);
            if (cmp < 0)
            {
                node = node.left;
            } else if (cmp > 0)
            {
                node = node.right;
            } else
                return node;
        }
        return null;
    }

    static class RBNode<K extends Comparable<K>, V>
    {
        private RBNode parent;
        private RBNode left;
        private RBNode right;
        private boolean color;
        private K key;
        private V value;

        public RBNode()
        {
        }

        public RBNode(K key, V value, RBNode parent)
        {
            this.parent = parent;
            this.color = BLACK;
            this.key = key;
            this.value = value;
        }

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

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

我是向这位老兄学习的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ReflectMirroring

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

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

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

打赏作者

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

抵扣说明:

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

余额充值