删除操作
1. 在纯函数式的环境下,纯函数式的数据结构决定了树不是真的被改变了,实际上是重建一棵树。(大多数函数式编程环境使用一种名叫Persistent的方法,可以复用树中没有改变的部分,从而减小重建的开销)。
利用一个双重黑色的引入。将删除节点的颜色(黑色)保存在其父节点中,如果父节点红色,则染成黑色,如果父节点是黑色,就是双重黑色。
2、结点的兄弟结点为红色;
3、结点的兄弟结点为黑色,同时其子结点也均为黑色;
4、结点的兄弟结点为黑色,同时兄弟结点的左子结点为红色,右子结点为黑色;
5、结点的兄弟结点为黑色,同时兄弟结点的右子结点为红色,左子结点为红色;删除之后通过调整,改变旋转和调整颜色维持红黑树的性质。
注意:x是指向于非根节点的一个双重黑色的节点。
情形3:x(A)的兄弟节点w(D)是黑色,兄弟节点的左子节点(C)为红色, 右子节点(D)为黑色。

此时交换w.left.color(C)和w.color(D)的颜色,然后右旋。
情形4:兄弟节点的右子节点是红色

1. 在纯函数式的环境下,纯函数式的数据结构决定了树不是真的被改变了,实际上是重建一棵树。(大多数函数式编程环境使用一种名叫Persistent的方法,可以复用树中没有改变的部分,从而减小重建的开销)。
利用一个双重黑色的引入。将删除节点的颜色(黑色)保存在其父节点中,如果父节点红色,则染成黑色,如果父节点是黑色,就是双重黑色。
删除的过程:1、如果删除的这个节点是根节点,root = null。左右节点都为空,直接删除。直接删注意它的颜色是否为黑色,若是黑色删除了违反性质5;
2、如果删除的这个节点有一个子节点,让它的子节点替代它,再把它删除即可;
3、删除的节点的左右子节点都不是空,找他的替代节点(可能是它的左子节点,或者左子节点的右节点一直遍历下去,即左子树的max, 亦或是右子树的min),然后替代节点替代这个值,将删除节点删除。
删掉后的结果则分为好几种情况(下面的结点为替代替代结点后的结点):
1、结点为新的根,此时只是将所有的路径中都去除一个黑色结点,所以依然保持平衡;2、结点的兄弟结点为红色;
3、结点的兄弟结点为黑色,同时其子结点也均为黑色;
4、结点的兄弟结点为黑色,同时兄弟结点的左子结点为红色,右子结点为黑色;
5、结点的兄弟结点为黑色,同时兄弟结点的右子结点为红色,左子结点为红色;删除之后通过调整,改变旋转和调整颜色维持红黑树的性质。
注意:x是指向于非根节点的一个双重黑色的节点。
情形1:x(A)的兄弟节点w(D)是红色的。
情形2:x(A)的兄弟节点w(D)是黑色的,它的两个子节点C、E也是黑色的。
情形3:x(A)的兄弟节点w(D)是黑色,兄弟节点的左子节点(C)为红色, 右子节点(D)为黑色。

此时交换w.left.color(C)和w.color(D)的颜色,然后右旋。
情形4:兄弟节点的右子节点是红色

左旋。x(A)褪去一层黑色变为单黑色。B节点变为黑色。当x设置为根后,当while循环测试其循环条件时,结束循环。
参考代码:
//删除指定节点
public void delete(T element){
//获取要删除的节点 注意这里是通过查找而不是new
Node target = tree_search(element);
if(target.left != null && target.right != null){
//先找到目标节点中序遍历的前一个节点
//前一个节点显然在它的左子树中。相当于找左子树的最大值。
Node tmp = target.left;
while(tmp.right != null){
tmp = tmp.right;
}
target.data = tmp.data;
target = tmp;
}
// System.out.println(target);
//修复它的替换节点,如果该替换节点不为Null
Node replacement = (target.left != null ? target.left : target.right);
// System.out.println(replacement); --可以为null
if(replacement != null){
replacement.parent = target.parent;
//如果目标节点的父节点为null,那么目标节点自己是根节点
if(target.parent == null){
root = replacement;
}
//如果target是其父节点的左节点
else if(target == target.parent.left){
target.parent.left = replacement;
}
else{
target.parent.right = replacement;
}
//删除这个节点
target.left = target.right = target.parent = null;
//修复红黑树
if(target.color == BLACK){
rbDelect_Fixup(replacement);
}
}
//自身是根节点
else if(target.parent == null){
root = null;
}
else{
//target无子节点,把它当成虚的替换节点
//修复红黑树
if(target.color == BLACK){
rbDelect_Fixup(target);
}
if(target.parent != null){
if(target ==target.parent.left){
target.parent.left = null;
}
else if(target ==target.parent.right){
target.parent.right = null;
}
target.parent = null;
}
}
}
//删除节点后修复红黑树
private void rbDelect_Fixup(Node T) {
while(T != root && colorOf(T) == BLACK){
//T是其父节点的左节点
if(T == leftOf(parentOf(T))){
//获取它的兄弟节点
Node brother = rightOf(parentOf(T));
if(brother.color == RED){
//兄弟节点设置为黑色。
setColor(brother, BLACK);
//父节点设置为红色
setColor(parentOf(T), RED);
rotateLeft(parentOf(T));
//将兄弟节点设置为删除节点的父节点的右节点。
brother = rightOf(parentOf(T));
}
if(colorOf(leftOf(brother)) == BLACK && colorOf(rightOf(brother)) == BLACK){
//
setColor(brother, RED);
T = parentOf(T);
}
else{
//只有兄弟节点的右节点是黑色
if(colorOf(rightOf(brother)) == BLACK){
//左节点也设置为黑色
setColor(leftOf(brother), BLACK);
setColor(brother, RED);
rotateRight(brother);
brother = rightOf(parentOf(T));
}
//设置兄弟接待你的颜色和父节点一样
setColor(brother, colorOf(parentOf(T)));
//T的父节点设置成黑色
setColor(parentOf(T), BLACK);
//brother的右节点设置为黑色
setColor(rightOf(brother), BLACK);
rotateLeft(parentOf(T));
T = root;
}
}
//如果T是其父节点的右子节点
else{
//获取T的兄弟节点
Node brother = leftOf(parentOf(T));
if(brother.color == RED){
//兄弟节点设置为黑色。
setColor(brother, BLACK);
//父节点设置为红色
setColor(parentOf(T), RED);
rotateRight(parentOf(T));
//将兄弟节点设置为删除节点的父节点的右节点。
brother = leftOf(parentOf(T));
}
if(colorOf(leftOf(brother)) == BLACK && colorOf(rightOf(brother)) == BLACK){
setColor(brother, RED);
T = parentOf(T);
}
else{
//只有兄弟节点的左节点是黑色
if(colorOf(leftOf(brother)) == BLACK){
//brother的右节点也设置为黑色
setColor(rightOf(brother), BLACK);
setColor(brother, RED);
rotateLeft(brother);
brother = leftOf(parentOf(T));
}
//设置兄弟接待你的颜色和父节点一样
setColor(brother, colorOf(parentOf(T)));
//T的父节点设置成黑色
setColor(parentOf(T), BLACK);
//brother的右节点设置为黑色
setColor(rightOf(brother), BLACK);
rotateLeft(parentOf(T));
T = root;
}
}
}
setColor(T, BLACK);
}
参考书籍:《算法导论》《疯狂Java突破程序员基本功的16课》
以上就是这篇的主要内容,欢迎提出意见,此外图片制作粗糙,请见谅。谢谢!