红黑树的删除
在上文中 . 我们已经介绍和演示了红黑树的插入 , 本文来 介绍一下 红黑树的 删除 以及 删除之后的调整
整理完之后,感觉还是疑点重重…本文代码 是解析 hashmap 的 红黑树操作…多处有疑问…希望有大佬能帮我梳理一下具体的操作
基于 我们对 AVL树的理解 , 用相同的方式 进行红黑树的删除分类
- 被删除的 节点 没有左右子树
- 被删除的 节点 只有左右子树的其中一个
- 被删除的 节点 同时拥有左右子树
在这3大类的情况下 , 红黑树 同时又比 不同的树 多了一个 颜色维度 , 所以 再次细分 红 和 黑 表面上 有6种情况
不过不用害怕…大多数的情况 都不会发生, 好多种情况 之间 都能够重叠
话不多说看图学习 ( 后有总结 和 代码)
变化总结
每种情况遍历下来之后 - - 发现 还是比较复杂的…这里再整理一下
代码实现
突然发现实现起来 好像真的挺麻烦的- -…这里就截取 hashmap中的 红黑树操作… 大致整理了一下 它的思路 (删除平衡调节 那一块 看不太明白了)
/**
* Removes the given node, that must be present before this call.
* This is messier than typical red-black deletion code because we
* cannot swap the contents of an interior node with a leaf
* successor that is pinned by "next" pointers that are accessible
* independently during traversal. So instead we swap the tree
* linkages. If the current tree appears to have too few nodes,
* the bin is converted back to a plain bin. (The test triggers
* somewhere between 2 and 6 nodes, depending on tree structure).
*/
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;
TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
if (pred == null)
tab[index] = first = succ;
else
pred.next = succ;
if (succ != null)
succ.prev = pred;
if (first == null)
return;
if (root.parent != null)
root = root.root();
if (root == null
|| (movable
&& (root.right == null
|| (rl = root.left) == null
|| rl.left == null))) {
tab[index] = first.untreeify(map); // too small
return;
}
//--------------这些东西是在判断长度是不是小于6了 , 如果小于6 就会转为链表------------------
//下面才是正文
TreeNode<K,V> p = this, pl = left, pr = right, replacement;
if (pl != null && pr != null) { //首先去判断删除的点是不是有这2孩子
TreeNode<K,V> s = pr, sl;
while ((sl = s.left) != null) //寻找该点的后继节点作为替代
s = sl;
boolean c = s.red; s.red = p.red; p.red = c; //交换 删除点 和 代替点的 颜色
//------↓-↓----------↓----↓---------↓------↓-----
TreeNode<K,V> sr = s.right;
TreeNode<K,V> pp = p.parent;
if (s == pr) { // p was s's direct parent
p.parent = s;
s.right = p;
}
else {
TreeNode<K,V> sp = s.parent;
if ((p.parent = sp) != null) {
if (s == sp.left)
sp.left = p;
else
sp.right = p;
}
if ((s.right = pr) != null)
pr.parent = s;
}
p.left = null;
if ((p.right = sr) != null)
sr.parent = p;
if ((s.left = pl) != null)
pl.parent = s;
if ((s.parent = pp) == null)
root = s;
else if (p == pp.left)
pp.left = s;
else
pp.right = s;
//--------这一段代码是在交换 代替点 和删除点的 位置 ↑---------
//这边判断一下 被代替的位置 还有没有右子树...如果有的话 还需要进一步替代
//也就是 replacement != p 而且 这个替代的 一定是红色
if (sr != null)
replacement = sr;
else
replacement = p;
}
//-------↓↓↓↓↓↓↓↓↓↓--仅有一支的情况----------
else if (pl != null)
replacement = pl;
else if (pr != null)
replacement = pr;
//-------↑↑↑↑↑↑↑↑↑--仅有一支的情况-----------
else //没有分支的情况
replacement = p;
// -------------↓↓----- ↓↓↓↓↓ -----↓↓------------
if (replacement != p) { //如果还有代替的点 p 是删除的点 , 如果存在替代
TreeNode<K,V> pp = replacement.parent = p.parent;
if (pp == null)
root = replacement;
else if (p == pp.left)
pp.left = replacement;
else
pp.right = replacement;
p.left = p.right = p.parent = null;
}
// ---------↑----- 将p点和代替点进行交换 , 然后p点脱离树-----↑↑------------
//如果被删除的点是红色的...就不要调整平衡
TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
if (replacement == p) { // detach
TreeNode<K,V> pp = p.parent;
p.parent = null;
if (pp != null) {
if (p == pp.left)
pp.left = null;
else if (p == pp.right)
pp.right = null;
}
}
if (movable)
moveRootToFront(tab, r);
}
用于调整平衡的函数
//用来做删除的平衡 ( 被调用的情况 只有是在 p点为 红色的时候)
//一种情况 x 原本是p的孩子 (一定为 红色) 现在处于p的位置 , (p 已经被移除了)
//还有一种情况 x 就是 p (颜色 不确定)
//但是 这两种情况中 x 一定是叶子了 , 没有左右支
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {
for (TreeNode<K,V> xp, xpl, xpr;;) {
if (x == null || x == root)
return root;
else if ((xp = x.parent) == null) { //被代替的位置是根节点
x.red = false;
return x;
}
else if (x.red) { //第一种情况 处理到这里 就已经结束了以及 第二种情况中的 x是红色
x.red = false;
return root;
}
else if ((xpl = xp.left) == x) { //x 是黑色的...而且还在 左支上
/**
判断 x的兄弟节点 是红色的
黑(xp) 黑(xpr) 黑
/ \ 变色, xp左旋 / \ / \
x 红(xpr) ---------- > 红(xp) 黑 ---> 更新命名 红(xp) 黑
/ \ / \ / \
黑 黑 x(黑) 黑 x(黑) 黑(xpr)
**/
if ((xpr = xp.right) != null && xpr.red) {
xpr.red = false;
xp.red = true;
root = rotateLeft(root, xp);
xpr = (xp = x.parent) == null ? null : xp.right;
}
if (xpr == null) //x为黑的情况下 兄弟 为 null - -? 实在想不出这种情况
x = xp; //从这里开始 越来越奇怪!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//感觉 可能出现了什么偏差情况
else {
/**
?(xp)
/ \
x(黑) xpr(黑)
/ \
sl(?) sr(?)
**/
TreeNode<K,V> sl = xpr.left, sr = xpr.right;
/**
?(xp) 变色 ?(xp)
/ \ --------> / \
x(黑) xpr(黑) x(黑) xpr(红)
**/
if ((sr == null || !sr.red) &&
(sl == null || !sl.red)) {
xpr.red = true;
x = xp;
}
else {
/**
?(xp) 变色,对xpr右旋 ?(xp)
/ \ ------------> / \
x(黑) xpr(黑) x(黑) xpr(sl)(黑) <----命名调整
/ \
sl(红) (xpr)(红)
**/
if (sr == null || !sr.red) {
if (sl != null)
sl.red = false;
xpr.red = true;
root = rotateRight(root, xpr);
xpr = (xp = x.parent) == null ?
null : xp.right;
}
if (xpr != null) {
xpr.red = (xp == null) ? false : xp.red;
if ((sr = xpr.right) != null)
sr.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateLeft(root, xp);
}
x = root;
}
}
}
else { // 对称处理
if (xpl != null && xpl.red) {
xpl.red = false;
xp.red = true;
root = rotateRight(root, xp);
xpl = (xp = x.parent) == null ? null : xp.left;
}
if (xpl == null)
x = xp;
else {
TreeNode<K,V> sl = xpl.left, sr = xpl.right;
if ((sl == null || !sl.red) &&
(sr == null || !sr.red)) {
xpl.red = true;
x = xp;
}
else {
if (sl == null || !sl.red) {
if (sr != null)
sr.red = false;
xpl.red = true;
root = rotateLeft(root, xpl);
xpl = (xp = x.parent) == null ?
null : xp.left;
}
if (xpl != null) {
xpl.red = (xp == null) ? false : xp.red;
if ((sl = xpl.left) != null)
sl.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateRight(root, xp);
}
x = 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) {
if ((rl = p.right = r.left) != null)
rl.parent = p;
if ((pp = r.parent = p.parent) == null)
(root = r).red = false;
else if (pp.left == p)
pp.left = r;
else
pp.right = r;
r.left = p;
p.parent = r;
}
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) {
if ((lr = p.left = l.right) != null)
lr.parent = p;
if ((pp = l.parent = p.parent) == null)
(root = l).red = false;
else if (pp.right == p)
pp.right = l;
else
pp.left = l;
l.right = p;
p.parent = l;
}
return root;
}
感谢观看
希望有大佬指正错误! 谢谢(士下座)!