说明看注释
一、removeTreeNode
/**
* @param movable 处理时,是否移动其他节点
*/
final void removeTreeNode(HashMap<K, V> map, Node<K, V>[] tab, boolean movable) {
int n;
//数组为空直接返回
if (tab == null || (n = tab.length) == 0) {
return;
}
//计算当前节点的的位置
int index = (n - 1) & hash;
//找到这个位置上的第一个树节点first,并标记为root节点
TreeNode<K, V> first = (TreeNode<K, V>) tab[index], root = first, rl;
//succ 表示当前要删除的节点的后节点, pred 表示其前节点
TreeNode<K, V> succ = (TreeNode<K, V>) this.next, pred = this.prev;
if (pred == null) {
//如果pred节点不存在,则表示当前节点为根节点
//删除后succ节点成为根节点,用fist节点标记,并放在数组上
tab[index] = first = succ;
} else {
//如果pred节点存在
//则将pred节点的后节点指向succ节点
pred.next = succ;
}
if (succ != null) {
//如果succ节点存在,则将succ节点的前节点指向pred节点
succ.prev = pred;
}
if (first == null) {
//如果当前节点不存在,直接返回
return;
}
//如果root节点的父节点存在,说明当前root节点不是根节点
if (root.parent != null) {
//获取真实根节点
root = root.root();
}
//以上做法是先整理当前节点上的链表关系,接下来整理红黑树关系
//根据当root节点和它的左右节点的一些情况,判断红黑树节点的数量
if (root == null || root.right == null || (rl = root.left) == null || rl.left == null) {
//太小了,转换为链表
tab[index] = first.untreeify(map);
return;
}
//p 当前节点,pl p节点的左节点,pr p节点的右节点
//replacement p节点删除后代替他的节点
TreeNode<K, V> p = this, pl = p.left, pr = p.right, replacement;
if (pl != null && pr != null) {
//当删除p节点,但是他的左右节点不为空时,遍历他的右节点上的左子树(以下操作先让p节点和s节点交换位置,然后找到replacement节点替换他)
TreeNode<K, V> s = pr, sl;
while ((sl = s.left) != null) {
s = sl;
}
//通过上述操作,s节点是大于p节点的最小节点(替换他的节点)
//将s节点和p节点的颜色交换
boolean c = s.red;
s.red = p.red;
p.red = c;
//sr s节点的右节点
TreeNode<K, V> sr = s.right;
//pp p节点的父节点
TreeNode<K, V> pp = p.parent;
//如果pr节点就是s节点
if (s == pr) {
//交换他们的关系
p.parent = s;
s.right = p;
} else {
//获得s节点的父节点sp
TreeNode<K, V> sp = s.parent;
//将p节点的父节点指向sp,且sp节点存在
if ((p.parent = sp) != null) {
//判断s节点在sp节点的哪一侧,将p节点放在s节点的那一侧
if (s == sp.left) {
sp.left = p;
} else {
sp.right = p;
}
}
//将pr节点变成s节点的右节点,且pr节点存在
if ((s.right = pr) != null) {
//将s节点变成pr节点的父节点
pr.parent = s;
}
}
//因为s节点的性质,s节点没有左节点
//当下p节点和s节点交换了位置,所以将p节点的左节点指空
p.left = null;
//将sr节点的变成p节点的右节点,且sr节点存在
if ((p.right = sr) != null) {
//将p节点变成sr节点的父节点
sr.parent = p;
}
//将pl节点变成s节点的左节点,且pl节点存在
if ((s.left = pl) != null) {
//将s节点变成pl节点的父节点
pl.parent = s;
}
//如果pp节点不存在,那当前s节点就是根节点
if ((s.parent = pp) == null) {
//将root节点指向s节点
root = s;
} else if (p == pp.left) {
//如果pp节点存在,且p节点是pp节点的左节点
//将s节点变成pp节点的左节点
pp.left = s;
} else {
//将s节点变成pp节点的右节点
pp.right = s;
}
//如果sr节点存在
if (sr != null) {
//将replacement节点变成sr节点
replacement = sr;
} else {
//sr节点不存在,将replacement变成p节点
replacement = p;
}
} else if (pl != null) {
//如果pl节点存在,pr节点不存在,不用交换位置,pl节点成为replacement节点
replacement = pl;
} else if (pr != null) {
//如果pr节点存在,pl节点不存在,不用交换位置,pr节点成为replacement节点
replacement = pr;
} else {
//如果都不存在,p节点成为replacement节点
replacement = p;
}
//将以下判断跟上述判断分开看,仅以p节点的当前位置性质,对replacement节点进行操作
if (replacement != p) {
//如果replacement不是p节点
//将p节点的父节点pp变成replacement节点的父节点
TreeNode<K, V> pp = replacement.parent = p.parent;
//如果pp节点不存在
if (pp == null) {
//replacement节点成为根节点
root = replacement;
} else if (p == pp.left) {
//如果pp节点存在,根据p节点在pp节点的位置,设置replacement节点的位置
pp.left = replacement;
} else {
pp.right = replacement;
}
//将p节点的所有树关系关系指空
p.left = p.right = p.parent = null;
}
//如果p节点是红色,删除后不影响root节点,如果是黑色,找到平衡后的根节点,并用节点r表示
TreeNode<K, V> r = p.red ? root : balanceDeletion(root, replacement);
//如果p节点是replacement节点
if (replacement == p) {
//得到p节点父节点pp
TreeNode<K, V> pp = p.parent;
//将p节点的父节点指空
p.parent = null;
if (pp != null) {
//如果pp节点存在
//根据p节点的位置,将pp节点的对应位置指空
if (p == pp.left) {
pp.left = null;
} else if (p == pp.right) {
pp.right = null;
}
}
}
//移动新的跟节点到数组上
if (movable) {
moveRootToFront(tab, r);
}
}
二、balanceDeletion
static <K, V> TreeNode<K, V> balanceDeletion(TreeNode<K, V> root, TreeNode<K, V> x) {
//x 当前要删除的节点
//xp x节点的父节点
//xpl xp节点的左节点
//xpr xp节点的右节点
TreeNode<K, V> xp, xpl, xpr;
for (; ; ) {
if (x == null || x == root) {
//如果x节点为空,或x节点是根节点
return root;
} else if ((xp = x.parent) == null) {
//当xp节点为空时,说明x为根节点,将x节点设置为黑色,并返回x节点
x.red = false;
return x;
} else if (x.red) {
//x节点是红色,无需调整
x.red = false;
return root;
} else if ((xpl = xp.left) == x) {
//如果x节点为xpl节点
if ((xpr = xp.right) != null && xpr.red) {
//如果xpr节点不为空,且xpr节点是红色的
//将xpr设置为黑色,xp设置为红色
xpr.red = false;
xp.red = true;
//左旋
root = rotateLeft(root, xp);
//重新将xp节点指向x节点的父节点,并将xpr节点指向xp的右节点
xpr = (xp = x.parent) == null ? null : xp.right;
}
if (xpr == null) {
//若xpr节点不存在
//则将x节点指向xp节点向上调整
x = xp;
} else {
//sl xpr节点的左节点
//sr xpr节点的右节点
TreeNode<K, V> sl = xpr.left, sr = xpr.right;
if ((sr == null || !sr.red) &&
(sl == null || !sl.red)) {
//若sr节点为空或者sr节点是黑色的,且sl节点为空或者sl节点是黑色的
//将xpr节点变成红色
xpr.red = true;
//则将x节点指向xp节点向上调整
x = xp;
} else {
//sr和sl中存在一个红节点
if (sr == null || !sr.red) {
//此处说明sl是红节点,将sl节点设置为黑色
sl.red = false;
//将xpr节点设置为红色
xpr.red = true;
//右旋
root = rotateRight(root, xpr);
//将xpr节点重新指向xp节点的右节点
xpr = (xp = x.parent) == null ? null : xp.right;
}
if (xpr != null) {
//如果xpr节点不为空,让xpr节点与xp节点同色
xpr.red = (xp == null) ? false : xp.red;
//当sr节点不为空,变成黑色
if ((sr = xpr.right) != null) {
sr.red = false;
}
}
//存在xp节点
if (xp != null) {
//将xp节点设置为黑色
xp.red = false;
//进行左旋
root = rotateLeft(root, xp);
}
//将x节点指向root进行下一次循环时跳出
x = root;
}
}
} else {
//当x节点是右节点
if (xpl != null && xpl.red) {
//当xpl节点存在且为红色
//将xpl变为黑色,xp变为红色
xpl.red = false;
xp.red = true;
//右旋
root = rotateRight(root, xpl);
//将xpl节点重新指向xp节点的左节点
xpl = (xp = x.parent) == null ? null : xp.left;
}
if (xpl == null) {
//如果xpl节点不存在,则xp节点没有子节点了
//将x节点指向xp节点向上调整
x = xp;
} else {
//sl xpl节点的左节点
//sr xpl节点的右节点
TreeNode<K, V> sl = xpl.left, sr = xpl.right;
if ((sl == null || !sl.red) && (sr == null || !sr.red)) {
//若sr节点为空或者sr节点是黑色的,且sl节点为空或者sl节点是黑色的
//将xpl节点变成红色
xpl.red = true;
//则将x节点指向xp节点向上调整
x = xp;
} else {
//sr和sl中存在一个红节点
if (sl == null || !sl.red) {
//此处说明sr是红节点,将sr节点设置为黑色
sr.red = false;
//将xpr节点设置为红色
xpl.red = true;
//左旋
root = rotateLeft(root, xpl);
//将xpl节点重新指向xp节点的左节点
xpl = (xp = x.parent) == null ? null : xp.left;
}
//如果xpl节点存在
if (xpl != null) {
//使xpl节点与xp节点同色
xpl.red = (xp == null) ? false : xp.red;
//如果sl节点存在
if ((sl = xpl.left) != null) {
//将sl节点变为黑色
sl.red = false;
}
}
//如果xp节点存在
if (xp != null) {
//将xp节点设置为黑色
xp.red = false;
//右旋
root = rotateRight(root, xp);
}
//将x节点指向root进行下一次循环时跳出
x = root;
}
}
}
}
}