红黑树基础与代码 - 节点的插入(二)

一. 节点的插入

节点的插入会破坏红黑树结构,所以我们要做变色和旋转操作,节点的变色和旋转是为了修正被破坏的红黑树, 使其符合红黑树的规则,从新达到平衡状态。红黑树的节点插入与二叉查找树的插入的过程是一样的,只是最后多了一步平衡调整操作,插入到红色节点下时才需要调整,因为插入到红色节点下违反了两个红色节点不能相邻规则。

二. 插入规则

插入节点平衡调整的几种情况如下:
  • 情况一:新插入节点的父节点是红色,其父节点的兄弟节点也是红色时,通过变色操作调整平衡。
    此时将父节点和父节点的兄弟节点(叔叔节点)变为黑色,将祖父节点(父节点的父节点)变为红色,接下来以祖父节点为基础继续向上验证修复,但最后根节点必须为黑色

  • 情况二:新插入节点的父节点为红色,父节点的兄弟节点为黑色时
    父节点、祖父节点和新节点3个节点在同一方向上(一条直线),如果为偏左的一条直线(如:和这个“/”方向一致),此时需要右旋(对祖父节点)。
    如果为偏右的一条直线(如:和这个“\”方向一致),此时需要左旋。然后新节点的父节点变为黑色,其兄弟节点(原始的祖父节点)变为红色。

  • 情况三:新插入节点的父节点为红色,父节点的兄弟节点为黑色时,且父节点、祖父节点和新节点3个节点不在同一方向上(不是一条直线)。
    如果新节点是父节点的右子节点(此时,父节点在祖父节点的左侧,此时这三个节点构成这样“<”方向非直线),此时需要先左旋(变为一条直线)再右旋,两次旋转。
    如果新节点是父节点的左子节点(此时,父节点在祖父节点的右侧,此时这三个节点构成这样“>”方向非直线),此时需要先右旋(变为一条直线)再左旋,两次旋转。

三. 代码实现如下

 /// 在插入并修复
 func insertAndFix(insertNode: Node?) {
    var node = insertNode
    /// 新插入节点颜色设置默认未红色
    node?.color = .red
    // 不是根节点且父节点为红色且不为空
    while node != nil && node != root && node?.parent?.color == .red {
        /// 父节点在祖父节点的左侧
        if node?.parent == node?.parent?.parent?.left {
            /// 叔叔节点(祖父节点的儿子)
            let s = node?.parent?.parent?.right
            /// 叔叔节点为红色
            if s?.color == .red {
                /// 父节点设置为黑色 叔叔节点设置好为黑色 祖父节点设置为红色
                node?.parent?.color = .black
                s?.color = .black
                node?.parent?.parent?.color = .red
                node = node?.parent?.parent
            } else { /// 叔叔节点为黑色
                /// 插入节点为右节点时候 形状如 《
                if node == node?.parent?.right {
                    node = node?.parent
                    /// 左旋操作
                    leftROtate(node: node)
                }
                node?.parent?.color = .black
                node?.parent?.parent?.color = .red
                rightRotate(node: node?.parent?.parent)
            }
        } else { /// 对称的。 父节点在祖父节点右侧
            let s = node?.parent?.parent?.left
            /// 叔叔节点为红色
            if s?.color == .red {
                node?.parent?.color = .black
                s?.color = .black
                node?.parent?.parent?.color = .red
                node = node?.parent?.parent
            } else {
                /// 插入节点为右节点时候 形状如  >
                if node == node?.parent?.left {
                    node = node?.parent
                    /// 左旋操作
                    rightRotate(node: node)
                }
                node?.parent?.color = .black
                node?.parent?.parent?.color = .red
                leftROtate(node: node?.parent?.parent)
            }
        }
    }
    /// 根节点始终要为黑色
    root?.color = .black
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值