1.节点的删除
红黑树与二叉搜索树的删除节点过程一样,当删除节点存在两个子节点,会被转换为删除有一个子节点或不存在子节点的节点。
对于有一个子节点的节点删除,比较简单,不需要平衡调整,只需要将其子节点改为黑色即可。
2.删除规则
对于删除的节点有两个不为空的叶子节点,这种情况最为复杂,需要平衡调整。
删除节点平衡调整的情况有如下几种
- 待删除节点的兄弟节点是红色
- 待删除节点的兄弟节点是黑色,且兄弟节点的子节点都是黑色
- 待删除节点的兄弟节点是黑色,如果兄弟节点在右侧,且兄弟节点的左子节点是红色,右子节点是黑色。如果兄弟节点在左侧,就是兄弟节点的右子节点是红色,左节点是黑色
- 待删除节点的兄弟节点是黑色,如果兄弟节点在右侧,且兄弟节点的右子节点是红色,左子节点是任意颜色。如果兄弟节点在左侧,则就是兄弟节点的左子节点是红色,右子节点是任意色
3. 情况如下
-
情况一:首先改变父节点和兄弟节点颜色(兄弟节点变为黑色,父节点变为红色),再对父节点做一次旋转(红色的兄弟节点在右侧,左旋。红色的兄弟节点在左侧,右旋),操作后,红黑的规则没有被破坏,树的黑色高度没变化,原兄弟节点的一个子节点变成删除节点的新兄弟节点。 (处理完后变为 情况 2, 3, 4 情况继续进行处理)
-
情况二: 删除节点后其父节点的左子树比右子树黑高度小1,此时需要把兄弟节点改为红色,则左右子树黑高度就相同了。此时将删除节点的父节点变为新的节点,然后继续向上迭代调整,修正平衡。
-
情况三:兄弟节点在右侧时,交换兄弟节点和其左子节点(红色)的颜色,并对兄弟节点进行右旋,于是被删除节点的新兄弟是一个有红色右子节点的黑色节点。相反,兄弟节点在左侧时,交换兄弟节点和其右子节点(红色)的颜色,并对兄弟节点进行左旋,于是被删除节点的新兄弟是一个有红色左子节点的黑色节点,(处理后变成情况四继续处理)
-
情况四:兄弟节点在右侧时,兄弟节点和父节点交换颜色,把兄弟节点的右子节点设为黑色,并对删除节点的父节点做一次左旋转。
兄弟节点在左侧时,兄弟节点和父节点交换颜色,把兄弟节点的左子节点设为黑色,并对删除节点的父节点做一次右旋转。
4. 代码如下 (swift5)
/// 删除以及修复
func deleteAndFix(deleteNode: Node?) {
var node = deleteNode
/// 删除节点不为空 且 颜色为黑色
while node != nil && node?.color == .black {
/// 如果删除节点为左子树
if node == node?.parent?.left {
var sib = node?.parent?.right
/// 第一种情况: 父亲节点为黑色。兄弟节点为红色
if sib?.color == .red {
sib?.color = .black
node?.parent?.color = .red
leftROtate(node: node?.parent)
sib = node?.parent?.right
}
/// 情况二 父亲节点为黑色, 兄弟节点的子节点都为黑色
if sib?.left?.color == .black && sib?.right?.color == .black {
sib?.color = .red
node = node?.parent
} else {
/// 情况三 父亲节点为黑色, 兄弟节点为黑色,兄弟节点的左子节点为黑色,右子节点为红色
if sib?.right?.color == .black {
sib?.left?.color = .black
sib?.color = .red
rightRotate(node: sib)
sib = node?.parent?.right
}
/// 情况四 父亲节点为黑色, 兄弟节点为黑色,兄弟节点的右子节点为黑色,左子节点为红色
sib?.color = node?.parent?.color ?? .black //(nil 默认为黑色)
node?.parent?.color = .black
sib?.right?.color = .black
leftROtate(node: node?.parent)
node = root
}
} else { /// 对称的
var sib = node?.parent?.left
if sib?.color == .red {
sib?.color = .black
node?.parent?.color = .red
rightRotate(node: node?.parent)
sib = node?.parent?.left
}
if sib?.right?.color == .black && sib?.left?.color == .black {
sib?.color = .red
node = node?.parent
} else {
if sib?.left?.color == .black {
sib?.right?.color = .black
sib?.color = .red
leftROtate(node: sib)
sib = node?.parent?.left
}
sib?.color = node?.parent?.color ?? .black
node?.parent?.color = .black
sib?.left?.color = .black
rightRotate(node: node?.parent)
node = root
}
}
}
/// 根始终为黑色
node?.color = .black
}