本文主要解析java8中HashMap的红黑树源码部分,如有不懂可以先看我写的红黑树基础-第一篇和红黑树基础-第二篇
1.左旋
注意:图中节点标号跟下面代码中变量名一致,便于理解。
/**
* 红黑树节点左旋操作
* @param root 根节点
* @param p 旋转节点
* @return 新root节点
*/
static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
TreeNode<K,V> p) {
TreeNode<K,V> r, pp, rl;
if (p != null && (r = p.right) != null) {
//1.把r的左子树变成p的右子树,并标记为rl,即p->right=rl
if ((rl = p.right = r.left) != null)
//2.如果rl不为空,链起来,rl->parent=p
rl.parent = p;
//3.把p的父节点变成r的父节点,并标记为pp,即r->parent=pp
if ((pp = r.parent = p.parent) == null)
//4.如果pp为空,那么之前p是根节点,现在左旋后r变成根节点,root=r,并且根节点为黑色,r.red=false
(root = r).red = false;
//5.否则pp不为空,就判断p是否是pp的左孩子,如果是,旋转后r就是左孩子
else if (pp.left == p)
pp.left = r;
else
//6.否则就是右孩子
pp.right = r;
//7.最后完善树的父子关系,链起来
//r->left=p
r.left = p;
//p->parent=r
p.parent = r;
}
//最后返回新的root节点
return root;
}
2.右旋
/**
* 红黑树节点右旋操作
* @param root 根节点
* @param p 旋转节点
* @return 新root节点
*/
static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
TreeNode<K,V> p) {
TreeNode<K,V> l, pp, lr;
if (p != null && (l = p.left) != null) {
//1.把l的右子树变成p的左子树,并标记为lr,即p->left=lr
if ((lr = p.left = l.right) != null)
//2.如果lr不为空,链起来,lr->parent=p
lr.parent = p;
//3.把p的父节点变成l的父节点,并标记为pp,即l->parent=pp
if ((pp = l.parent = p.parent) == null)
//4.如果pp为空,那么之前p是根节点,现在右旋后l变成根节点,root=l,并且根节点为黑色,l.red=false
(root = l).red = false;
//5.否则pp不为空,就判断p是否是pp的右孩子,如果是,旋转后l就是右孩子
else if (pp.right == p)
pp.right = l;
else
//6.否则就是左孩子
pp.left = l;
//7.最后完善树的父子关系,链起来
//l->right=p
l.right = p;
//p->parent=l
p.parent = l;
}
//最后返回新的root节点
return root;
}
3.平衡插入
讲解平衡插入之前,我们直接从源码入手,如果感觉理解起来有困难,请先看懂我写的红黑树基础-第一篇
下面约定下面代码变量的命名规则,x为逻辑上待插入的节点(有可能是第一次插入,也有可能是自底向上调整时的插入)&#x