HashMap1.8 -- 红黑树 --完整代码和测试

完整代码和测试

package 红黑树;


import com.sun.org.apache.regexp.internal.RE;
import org.omg.CORBA.UNKNOWN;
import 二叉排序树.TwoTree;

/**
 * 红黑树   K:key(必须是可比较的   可以自定义比较规则)  V:value
 *
 *性质1:每个节点要么是黑色,要么是红色。
 *性质2:根节点是黑色。
 *性质3:每个叶子节点(NIL)是黑色。
 *性质4:每个红色节点的两个子节点一定都是黑色。
 *                  不能有两个红色节点相连。
 *性质5:任意一节点到每个叶子节点的路径都包含数量相同的黑结点。俗称:黑高!
 *性质6:如果一个节点存在黑子节点,那么该结点肯定有两个子节点
 */


/**
 * 插入后修复红黑树平衡的方法
 *     |---情景1:红黑树为空树            变红为黑即可
 *     |---情景2:插入节点的key已经存在   直接替换Value即可
 *     |---情景3:插入节点的父节点为黑色
 *                 如果父亲为黑树  不需要调整(只需要判断以下几种情况)
 *
 *     情景4 需要咱们去处理
 *     |---情景4:插入节点的父节点为红色
 *          |---情景4.1:叔叔节点存在,并且为红色(父-叔 双红)
 *                       父亲 和 叔叔 变黑  爷爷变红  因为爷爷颜色变了  需要对爷爷 及其以上进行调整
 *          |---情景4.2:叔叔节点不存在,或者为黑色,父节点为爷爷节点的左子树
 *               |---情景4.2.1:插入节点为其父节点的左子节点(LL情况)
 *                          父亲变黑 爷爷变红  右旋 不需要再调整
 *               |---情景4.2.2:插入节点为其父节点的右子节点(LR情况)
 *                          左旋 成为  LL情况 再递归解决LL情况
 *          |---情景4.3:叔叔节点不存在,或者为黑色,父节点为爷爷节点的右子树
 *               |---情景4.3.1:插入节点为其父节点的右子节点(RR情况)
 *               |---情景4.3.2:插入节点为其父节点的左子节点(RL情况)
 */

public class RedAndBlackTree <K extends Comparable<K>,V>
{
   
    // 红色节点  和 黑色节点
    private static final boolean RED = true;
    private static final boolean BLACK = false;

    //红黑树的树根
    private RBNode root;

    public RBNode getRoot() {
   
        return root;
    }


    /**
     * 测试  用的
     */
    public void insertNodes(K keys[])
    {
   
        for (int i =0;i<keys.length;i++)
        {
   
            RBNode node = new RBNode (RED,null,null,null,keys[i],null);
            insertNode(node);
        }
    }

    /***
     * 插入算法
     */
    public void insertNode(K key , V value)
    {
   
        RBNode node = new RBNode (RED,null,null,null,key,value);
        insertNode(node);
    }

    /**
     * 内部 核心插入算法
     * @param node
     */
    private void insertNode(RBNode node)
    {
      //parent 指向 被插入节点的父节点
        RBNode parent = null;
        RBNode p = root;  //p  用于循环遍历的
        while (p != null)
        {
   
            parent = p;
            int num = node.key.compareTo (p.key);
            if(num <0) // node < p
            {
   
                p = p.leftNode;
            }
            else if(num > 0)
            {
   
                p = p.rightNode;
            }
            else   //相等情况下  就直接覆盖 value 即可
            {
   
                p.setV (node.v);
                return;
            }
        }
        //不为空 树 时候 parent指向待插入节点的父亲节点
        node.parent = parent;

        if(parent != null)
        {
   
            if(node.key.compareTo (parent.key)<0)
            {
   
                parent.leftNode = node;
            }
            else
            {
   
                parent.rightNode = node;
            }
        }
        //代表  红黑树  一个节点都没有  即  空树情况
        else
        {
   
            this.root = node;
            this.root.setColor (BLACK);
            return;
        }

        //插入之后需要进行修复红黑树,让红黑树再次平衡。
        insertFixUp(node);
    }

    /**
     * 平衡 红黑树
     * @param node
     */
    /**
     * 插入后修复红黑树平衡的方法
     *     |---情景1:红黑树为空树            上一个方法已经实现  (变红为黑即可)
     *     |---情景2:插入节点的key已经存在   上一个方法已经实现 (直接替换即可)
     *     |---情景3:插入节点的父节点为黑色
     *                 如果父亲为黑树  不需要调整(只需要判断以下几种情况)
     *
     *     情景4 需要咱们去处理
     *     |---情景4:插入节点的父节点为红色
     *          |---情景4.1:叔叔节点存在,并且为红色(父-叔 双红)
     *          |---情景4.2:叔叔节点不存在,或者为黑色,父节点为爷爷节点的左子树
     *               |---情景4.2.1:插入节点为其父节点的左子节点(LL情况)
     *               |---情景4.2.2:插入节点为其父节点的右子节点(LR情况)
     *          |---情景4.3:叔叔节点不存在,或者为黑色,父节点为爷爷节点的右子树
     *               |---情景4.3.1:插入节点为其父节点的右子节点(RR情况)
     *               |---情景4.3.2:插入节点为其父节点的左子节点(RL情况)
     */
    private void insertFixUp(RBNode node)
    {
   
        // node 插入进去的节点   parent:父亲节点     gparent:爷爷节点
        RBNode parent = getParent (node);
        RBNode gparent = getParent (parent);

        //外层判断   父亲节点存在,且为红色,那么爷爷节点一定存在 且为黑色
        if(parent != null && isRed (parent))
        {
   
            /**
             * 里面分两大类情况: 父亲在爷爷的左边  还是 爷爷的右边
             */
            //父亲在 左边情况
            if(gparent.leftNode == parent)
            {
   
                //叔叔节点
                RBNode uncle = gparent.rightNode;
                //叔叔和父亲 双红情况下  先进行变色操作
                if(uncle != null && isRed (uncle))
                {
   
                    setBlack (parent);
                    setBlack (uncle);
                    setRed (gparent);
                    //对爷爷节点 再进行调整 因为爷爷节点变色 肯定对上层 有影响;
                    insertFixUp (gparent);
                    return;
                }

                // 叔叔节点 为黑色 或者 不存在   这时候 要分是   LL 情况  还是LR情况
                if(uncle == null || !isRed (uncle))
                {
   
                    //LL情况  变色 再 右旋
                    /**
                     *      pp(黑)          pp(红)                p(黑)
                     *     / \              / \      右旋         /   \
                     *    p(红)   ->     p(黑)     ->         x(红)  pp(红)
                     *   /                /
                     *  x (红)         x(红)
                     */
                    //因为 此时  此模型的根节点 颜色(黑色 没变 因此不需要要 再次调整)
                    if(parent.leftNode == node)
                    {
   
                        setBlack (parent);
                        setRed (gparent);
                        rightRotate (gparent);
                    }
                    //LR情况  先对parent进行 左旋  -> LL情况 然后 再按LL情况处理;
                    if(parent.rightNode == node)
                    {
   
                        //这里一定要对 (父) parent  左旋
                        leftRotate (parent);
                        //左旋完成后 parent 成了 插入节点调正的地方了
                        /**
                         *      gp(黑)          gp(红)
                         *     / \              / \
                         *    parent(红) -> node(红)
                         *    \               /
                         *     node (红)  parent(红)
                         */
                        //下轮的 调整处理  LL  情况
                        insertFixUp (parent);
                        //这里的  return 加不加无所谓  因为上边 insertFixUp 完成了对根节点的 变黑操作
                        return;
                    }
                }
            }
            //父亲节点 在  右边的时候
            else
            {
   
                RBNode uncle = gparent.leftNode;
                //4.1 父亲 和 叔叔 双红
                if(uncle !=
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值