HashMap中的红黑树插入方法balanceInsertion
摘要:
HashMap是java最常用的容器之一,本文会通过阅读源码的方式来理解HashMap中是如何进行红黑树的插入
红黑树的插入详细解析可以看下我这篇文章
红黑树详解(二)红黑树的插入(附动图和案例)
简单的用一张图概括一下
源码及注释如下,需要注意的是参数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左旋
}
}
}
}
}
}