HashMap的工作原理和源码实现(三)红黑树的插入


HashMap中的红黑树插入方法balanceInsertion


摘要:

    HashMap是java最常用的容器之一,本文会通过阅读源码的方式来理解HashMap中是如何进行红黑树的插入

红黑树的插入详细解析可以看下我这篇文章
红黑树详解(二)红黑树的插入(附动图和案例)
简单的用一张图概括一下
HashMap的工作原理和源码实现(三)红黑树的插入_第1张图片
源码及注释如下,需要注意的是参数root表示根节点,x表示需要旋转的结点,返回值就是新的根节点,红黑树的插入平衡中可能会涉及根节点的改变,因此参数传入原来的根节点来修改。

static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
                                                    TreeNode<K,V> x) {
            x.red = true;             //所有插入结点初始值都为红色
            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) { //xp为x父结点,xpp为x的祖父结点,xppl为x的祖父结点的左子结点,xppr为x的祖父结点的右子结点
                if ((xp = x.parent) == null) { //插入结点是根结点,直接变黑色,返回x
                    x.red = false;
                    return x;
                }
                else if (!xp.red || (xpp = xp.parent) == null) //情况2,插入结点父结点为黑色
                    return root; //不用操作,直接返回原来的根结点
                //下面是情况3,父结点是红结点
                if (xp == (xppl = xpp.left)) { //x的父结点是祖父结点的左子结点
                    if ((xppr = xpp.right) != null && xppr.red) { //情况3.1,叔叔结点是红结点
                        xppr.red = false;//x的叔叔结点变黑色
                        xp.red = false; //x的父结点变为黑色
                        xpp.red = true; //x的祖父结点变红色
                        x = xpp;  //把祖父结点作为新的插入结点
                    }
                    else {
                        if (x == xp.right) {//情况3.2.2叔叔结点不存在或者为黑色,插入结点x是父结点p的右子结点
                            root = rotateLeft(root, x = xp); 对x的父结点左旋,把p设为插入结点,之后转到下面情况3.2.1
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {//情况3.2.1 叔叔结点不存在或者为黑色,插入结点x是父结点p的左子结点
                            xp.red = false;//x的父结点xp变黑
                            if (xpp != null) {
                                xpp.red = true; //x的祖父结点xpp变为红
                                root = rotateRight(root, xpp); //对x的祖父结点右旋
                            }
                        }
                    }
                }
                else { //x的父结点是祖父结点的右子结点
                    if (xppl != null && xppl.red) {//情况3.1 叔叔结点是红色
                        xppl.red = false;//叔叔结点变黑
                        xp.red = false;//父结点变黑
                        xpp.red = true;//祖父结点变红
                        x = xpp;//把祖父结点设置为新的插入结点
                    }
                    else {
                        if (x == xp.left) {//情况3.3.2叔叔结点不存在或者为黑色,插入结点x是父节点p的左子结点
                            root = rotateRight(root, x = xp);//duix的父结点右旋,把p设置为新的插入结点,之后转到下面情况3.3.1
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {//情况3.3.1 叔叔结点不存在或者为黑色,插入结点x是父结点p的右子结点
                            xp.red = false;//x的父结点xp变黑
                            if (xpp != null) {
                                xpp.red = true;//x的祖父结点xpp变为红
                                root = rotateLeft(root, xpp);//对x的祖父结点xpp左旋
                            }
                        }
                    }
                }
            }
        }

你可能感兴趣的:(java,数据结构与算法,java,hashmap,二叉树,算法,数据结构)