红黑树基础与代码 - 节点的删除(三)

24 篇文章 0 订阅
19 篇文章 0 订阅

1.节点的删除

红黑树与二叉搜索树的删除节点过程一样,当删除节点存在两个子节点,会被转换为删除有一个子节点或不存在子节点的节点。
对于有一个子节点的节点删除,比较简单,不需要平衡调整,只需要将其子节点改为黑色即可。

2.删除规则

对于删除的节点有两个不为空的叶子节点,这种情况最为复杂,需要平衡调整。
删除节点平衡调整的情况有如下几种

  1. 待删除节点的兄弟节点是红色
  2. 待删除节点的兄弟节点是黑色,且兄弟节点的子节点都是黑色
  3. 待删除节点的兄弟节点是黑色,如果兄弟节点在右侧,且兄弟节点的左子节点是红色,右子节点是黑色。如果兄弟节点在左侧,就是兄弟节点的右子节点是红色,左节点是黑色
  4. 待删除节点的兄弟节点是黑色,如果兄弟节点在右侧,且兄弟节点的右子节点是红色,左子节点是任意颜色。如果兄弟节点在左侧,则就是兄弟节点的左子节点是红色,右子节点是任意色

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
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值