删除及Java代码实现-红黑树-数据结构和算法

删除及Java代码实现-红黑树-数据结构和算法

目录




内容

前面的章节我们了解了红黑树的基础知识、红黑树的基础操作、添加,那么下面我们继续探索下红黑的数的删除。

1、分析

  • 删除思路:黑红数节点删除 涉及节点移除及节点调整。
  • 节点(移除):如果目标节点有后继(或者前驱节点),那么节点和颜色互换,要移除节点变为后继(或者前驱)节点;如何没有那么要移除的节点还是当前节点。
  • 节点(调整):如何要移除节点为后继(或者前驱)节点,判断是否有右节点(或者左节点),有则调整节点为右节点(或者左节点);没有右节点(或者左节点),调整节点为后继(或者前驱)节点。如何没有后继(或者前驱)节点, 调整节点为当前节点。
  • 具体移除和调整步骤下面分情况具体分析

为什么要用节点的后继或者前驱来替换目标节点呢?

2、具体步骤

2.1、移除

  1. 如果根节点root为空,结束。

  2. 找到要删除的节点p(参考二叉搜索树的查找)

  3. 如果节点p为空,结束

  4. pl为p的左节点,pr为p的右节点,replacement为要调整的节点(根据情况设置值) .
    情况图示:在这里插入图片描述

  5. 如果p的左节点pl,右节点pr都不为空

    1. 那么一定存在后继节点s,查找后继节点s
    2. s与p互换颜色,后续根据情况互换位置
    3. sr为s的右节点,pp为p的父节点
    4. 如果s == pr(后继节点为p的右节点),图示:
      1. p的父节点指向s
      2. s的右节点指向p
    5. 否则,sp为s的父节点
    6. p的父节点指向sp,如果不为空
      1. 如果s是sp的左节点,那么sp的左节点指向p
      2. 否则sp右节点指向p
    7. s右节点指向pr,如果不为空
      1. pr的父节点指向s
    8. p的左节点设置为null
    9. p的右节点指向sr,如果不为空
      1. sr的父节点指向p
    10. s的左节点指向pl,如果不为空
      1. pl的父节点指向s
    11. s的父节点指向pp,如果为空
      1. 根据点root指向s
    12. 否则,判断如果p是pp的左节点
      1. pp的左节点指向s
    13. pp的右节点指向s
    14. 如果sr不为空
      1. replacement设置为sr
    15. 否则replacement设置为p
  6. 如果pl不为空

    1. replacement设置为pl
  7. 如果pr不为空

    1. replacement设置为pr
  8. 否则replacement设置为p

  9. 如果replacement 不等p,开始移除p节点,图示:在这里插入图片描述

    1. replacement的父节点指向p的父节点pp
    2. 如果pp为空(根节点)
      1. root指向replacement
    3. 否则判断p是否pp的左节点
      1. pp的左节点指向replacement
    4. 否则pp的右节点指向replacement
    5. p左节点、右节点、父节点置空,p节点移除完毕
  10. 如果p为红色,则不需要调整;如果p为黑色,开始运行调整程序,具体步骤见下面

  11. 如果replacement 等于p,红黑树已经调整完成,开始移除p操作

    1. pp为p的父节点
    2. p的父节点置空
    3. 如果pp不为空
      1. 如果p是pp的左节点
        1. pp的左节点置空
      2. 否则pp的右节点置空
  12. 红黑树元素个数减1 到此红黑树删除完毕

2.2、调整

以左子树为例,由之前的步骤得知,左侧现在是少1个黑色的节点的,那么为了调整符合性质5,需要向右子树借一个黑色节点。

根据上述程序,设置要调整的目标节点x,具体步骤如下:

  1. 循环开始
  2. 如果x为空或者x是根节点,结束
  3. 如果x的父节点xp为空(根节点)
    1. x设为黑色,结束
  4. 如果x颜色为红色(没有影响,查看红黑树性质)
    1. x设为黑色,结束
  5. 如果xp的左节点xpl等于x
    1. 如果xp的右节点xpr不为空且为红色,图示:在这里插入图片描述

      1. xpr颜色设置为红色,xp颜色设置为红色
      2. 对xp节点左旋
    2. 如果xpr 为空

      1. x设置为xp
    3. 否则,xpr不为空且为黑色

      1. sl为xpr的左节点,sr为xpr的右节点
      2. 如果sl或者sr都不为红色
        1. xpr设置为红色
        2. x设置为xp
      3. 否则-sl或者sr至少有一个为红色(非空)
        1. 如果sr为空或者黑色,那么sl一定为红色,图示:在这里插入图片描述

          1. sl设置为黑色,xpr设置为红色
          2. 对xpr右旋
        2. 如果xpr不为空,则sr为红色

          1. xpr设置为xp的颜色
          2. xpr的右节点指向sr,如果不为空
            1. sr设置为黑色
        3. 如果xp不为空

          1. xp设置为黑色
          2. 对xp左旋
  6. 否则x为xp的右节点,不在分析,可结合上面左节点情况对照分析
  7. 重复选好,直至符合1或者2 结束循环(调整)

3、Java代码

  • 删除代码
// 删除
    public void removeRBTreeNode(K k) {
        if (root == null) {
            return;
        }
        RBNode<K, V> p = findNode(k);
        if (p == null)
            return;

        RBNode<K,V>  pl = p.left, pr = p.right, replacement;
        if (pl != null && pr != null) {
            RBNode<K,V> s = pr, sl;
            while ((sl = s.left) != null) // find successor
                s = sl;
            boolean c = s.red; s.red = p.red; p.red = c; // swap colors
            RBNode<K,V> sr = s.right;
            RBNode<K,V> pp = p.parent;
            if (s == pr) { // p was s's direct parent
                p.parent = s;
                s.right = p;
            }
            else {
                RBNode<K,V> sp = s.parent;
                if ((p.parent = sp) != null) {
                    if (s == sp.left)
                        sp.left = p;
                    else
                        sp.right = p;
                }
                if ((s.right = pr) != null)
                    pr.parent = s;
            }
            p.left = null;
            if ((p.right = sr) != null)
                sr.parent = p;
            if ((s.left = pl) != null)
                pl.parent = s;
            if ((s.parent = pp) == null)
                root = s;
            else if (p == pp.left)
                pp.left = s;
            else
                pp.right = s;
            if (sr != null)
                replacement = sr;
            else
                replacement = p;
        }
        else if (pl != null)
            replacement = pl;
        else if (pr != null)
            replacement = pr;
        else
            replacement = p;
        if (replacement != p) {
            RBNode<K,V> pp = replacement.parent = p.parent;
            if (pp == null)
                root = replacement;
            else if (p == pp.left)
                pp.left = replacement;
            else
                pp.right = replacement;
            p.left = p.right = p.parent = null;
        }

        RBNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);

        if (replacement == p) {  // detach
            RBNode<K,V> pp = p.parent;
            p.parent = null;
            if (pp != null) {
                if (p == pp.left)
                    pp.left = null;
                else if (p == pp.right)
                    pp.right = null;
            }
        }
        size--;
    }
  • 调整代码
// 代码调整(删除)
    static <K,V> RBNode<K,V> balanceDeletion(RBNode<K,V> root,
                                                       RBNode<K,V> x) {
        for (RBNode<K,V> xp, xpl, xpr;;)  {
            if (x == null || x == root)
                return root;
            else if ((xp = x.parent) == null) {
                x.red = false;
                return x;
            }
            else if (x.red) {
                x.red = false;
                return root;
            }
            else if ((xpl = xp.left) == x) {
                if ((xpr = xp.right) != null && xpr.red) {
                    xpr.red = false;
                    xp.red = true;
                    root = rotateLeft(root, xp);
                    xpr = (xp = x.parent) == null ? null : xp.right;
                }
                if (xpr == null)
                    x = xp;
                else {
                    RBNode<K,V> sl = xpr.left, sr = xpr.right;
                    if ((sr == null || !sr.red) &&
                            (sl == null || !sl.red)) {
                        xpr.red = true;
                        x = xp;
                    }
                    else {
                        if (sr == null || !sr.red) {
                            sl.red = false;
                            xpr.red = true;
                            root = rotateRight(root, xpr);
                            xpr = (xp = x.parent) == null ?
                                    null : xp.right;
                        }
                        if (xpr != null) {
                            xpr.red = xp.red;
                            if ((sr = xpr.right) != null)
                                sr.red = false;
                        }
                        if (xp != null) {
                            xp.red = false;
                            root = rotateLeft(root, xp);
                        }
                        x = root;
                    }
                }
            }
            else { // symmetric
                if (xpl != null && xpl.red) {
                    xpl.red = false;
                    xp.red = true;
                    root = rotateRight(root, xp);
                    xpl = (xp = x.parent) == null ? null : xp.left;
                }
                if (xpl == null)
                    x = xp;
                else {
                    RBNode<K,V> sl = xpl.left, sr = xpl.right;
                    if ((sl == null || !sl.red) &&
                            (sr == null || !sr.red)) {
                        xpl.red = true;
                        x = xp;
                    }
                    else {
                        if (sl == null || !sl.red) {
                            sr.red = false;
                            xpl.red = true;
                            root = rotateLeft(root, xpl);
                            xpl = (xp = x.parent) == null ?
                                    null : xp.left;
                        }
                        if (xpl != null) {
                            xpl.red = xp.red;
                            if ((sl = xpl.left) != null)
                                sl.red = false;
                        }
                        if (xp != null) {
                            xp.red = false;
                            root = rotateRight(root, xp);
                        }
                        x = root;
                    }
                }
            }
        }
    }
  • 测试代码
 public static void testRBTree() {
        RBTree<Integer, String> rbTree = new RBTree<>();
        rbTree.add(1, "aaa");
        rbTree.add(23, "sdf");
        rbTree.add(63, "434");
        rbTree.add(634, "r4f");
        rbTree.add(223, "2342");
        rbTree.add(22, "fwff");
        System.out.println(rbTree);
        System.out.println(rbTree.size());
//        System.out.println(rbTree.findNode(1));
        rbTree.removeRBTreeNode(223);
        System.out.println(rbTree);
        System.out.println(rbTree.size());
    }
	
 // 测试结果
 [(1,aaa,黑),(22,fwff,红),(23,sdf,黑),(63,434,红),(223,2342,黑),(634,r4f,红)]
6
[(1,aaa,黑),(22,fwff,红),(23,sdf,黑),(63,434,红),(634,r4f,黑)]
5

红黑树学到这里后 ,有了不少疑问,相关的思考和讨论,留到下一篇将,先到这里。

后记

  欢迎交流,本人QQ:806797785

项目源代码地址:https://gitee.com/gaogzhen/algorithm.git
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gaog2zh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值