上一篇讲了插入调整,现在来讲删除调整。红黑树的删除无疑是最难的,抛开调整,红黑树的插入删除都跟选择二叉树一样,所以前面的步骤网上很多了,在这里只讲如何调整,以满足红黑树性质。
还是从头到尾理一下吧...
先定义一下,删除节点为d,真实删除节点为reald,顶替节点为x,x的兄弟节点即前reald的兄弟节点为w。
找到要删除的节点d。
1.若d有一个子节点,则直接用d的子节点x顶替d以达到删除的目的。此时reald就是d。
2.若没有子节点,则直接用x(此时x为空节点)顶替d。此时reald就是d。
3.若有两个子节点,则寻找d的前驱或者后继reald(也是就是d的左子树下最大的节点或者右子树下最小的节点)。将后继节点reald的值赋给d,并删除reald(用reald的子节点x顶替reald)
上面就是选择二叉树的删除方法,红黑树的话只是多一步调整步骤。
删除后调整以满足红黑树性质
若真实删除的节点reald为红色,那么删除后对红黑树性质没有影响,则不用调整。
若reald为黑色
循环条件(顶替节点x不为root,且x的颜色为黑),跳出循环后记得将x颜色赋为黑!
1.如果顶替节点x为红色,则将x变为黑色,调整结束。
2.若顶替节x点为黑色
case1 若x的兄弟节点为红色(因为x顶替了reald,也就是原reald的兄弟节点为红)
=》
=》
如图删除节点17,15为前驱节点,则reald为15,顶替节点x为空节点,兄弟节点11为红色。
处理方法:将兄弟节点变为黑色,x的父节13点变为红色,以x的父节点右旋(如果x是父节点的左儿子则左旋)。
旋转后,x的兄弟节点变为黑色,即上面最后一幅图的12,进入case2。这一步的目的就是让x的兄弟节点变黑。
case2 若x的兄弟节点w为黑色
case2.1 w的左右子节点都为黑 (删除17,15为前驱节点,则reald为15,顶替节点x为空节点,兄弟节点12为黑色)
=》
=》
处理方法:令w为红,x=x.parent,然后就继续循环迭代(因为原先是13的右分支少了一个黑,现在是13的左右分支都少了一个黑)
case2.2 当w为左子树时,w的左节点为红(或者当w为右子树时,w的右子节点为红)
=》
删除18,w为15。
处理方法:令w的左子树为黑(或者令w的右子树为黑),交换w和w父节点的颜色,以父节点右旋(左旋),达到平衡,令x=root跳出循环。
case2.3 当w为右子树时,w的右节点为黑,左节点肯定为红,不然就是case2.1(或者当w为左子树时,w的左子节点为黑)
=》
删除12,w为17,w右节点为黑。
处理方法:(目的是把情况搞成case2.2),令w为红,w的左节点为黑(或者w的右节点为黑),以W右旋(或者左旋)。得到情况case2.2。
总结:
1.如果顶替节点x为红色,则将x变为黑色,调整结束。
2.若顶替节x点为黑色
case1 若x的兄弟节点2为红色
case2 若x的兄弟节点w为黑色
case2.1 w的左右子节点都为黑
case2.2 当w为左子树时,w的左节点为红(或者当w为右子树时,w的右子节点为红)
case2.3 当w为右子树时,w的右节点为黑,左节点肯定为红,不然就是case2.1(或者当w为左子树时,w的左子节点为黑)
golang代码
func (rbt *RBTree) Delete(data float64) {
/*getMin := func(node *TreeNode) *TreeNode {
if node == nil {
return nil
}
for {
if node.lchild != nil {
node = node.lchild
} else {
return node
}
}
}*/
getMax := func(node *TreeNode) *TreeNode {
if node == NilNode {
return NilNode
}
for {
if node.rchild != NilNode {
node = node.rchild
} else {
return node
}
}
}
node := rbt.Search(data)
if node == NilNode {
return
}
dnode := node //真实删除节点reald
x := node //顶替节点
if node.lchild == NilNode && node.rchild != NilNode {
x = node.rchild
} else if node.rchild == NilNode && node.lchild != NilNode {
x = node.lchild
} else if node.rchild != NilNode && node.lchild != NilNode {
//dnode := getMin(node.rchild)
dnode = getMax(node.lchild)
node.data = dnode.data
x = dnode.lchild
} else {
x = NilNode
}
//顶替节点和删除节点的父节点关联
if dnode == rbt.root {
log.Println(dnode, rbt.root)
rbt.root = NilNode
return
} else if dnode == dnode.parent.lchild {
dnode.parent.lchild = x
} else if dnode == dnode.parent.rchild {
dnode.parent.rchild = x
}
x.parent = dnode.parent
if dnode.color == "black" {
rbt.deleteBalanceFixup(x)
}
}
func (rbt *RBTree) deleteBalanceFixup(x *TreeNode) {
for x != rbt.root && x.color == "black" {
if x == x.parent.lchild { //x是左子树的情况
w := x.parent.rchild
if w.color == "red" { //case 1
w.color = "black"
x.parent.color = "red"
rbt.LeftRotate(x.parent)
w = x.parent.rchild
}
//下面是w为黑的三种情况
if w.lchild.color == "black" && w.rchild.color == "black" {
w.color = "red"
x = x.parent
} else {
if w.rchild.color == "black" {
w.lchild.color = "black"
w.color = "red"
rbt.RightRotate(w)
w = x.parent.rchild
}
//右孩子为红
w.rchild.color = "black"
w.color, x.parent.color = x.parent.color, w.color
rbt.LeftRotate(x.parent)
x = rbt.root //跳出循环
}
} else {
w := x.parent.lchild
if w.color == "red" { //case 1
w.color = "black"
x.parent.color = "red"
rbt.RightRotate(x.parent)
w = x.parent.lchild
}
//下面是w为黑的三种情况
if w.lchild.color == "black" && w.rchild.color == "black" {
w.color = "red"
x = x.parent
} else {
if w.lchild.color == "black" {
w.rchild.color = "black"
w.color = "red"
rbt.LeftRotate(w)
w = x.parent.lchild
}
//左孩子为红
w.lchild.color = "black"
w.color, x.parent.color = x.parent.color, w.color
rbt.RightRotate(x.parent)
x = rbt.root //跳出循环
}
}
}
x.color = "black"
}