利用上班摸鱼时间,手撕红黑树(Java代码实现)

操作术语

红黑树节点主要成员包括指向左孩子、右孩子、父节点的引用,一个boolean类型的变量标识是红或黑。
对于查询操作,跟二叉搜索树一样
插入、删除可能会影响红黑树的平衡,需要通过旋转和变色维护。

左旋逻辑:
设对节点p左旋,其目标为使节点p成为其右孩子节点的左孩子节点,操作为修改节点p和节点p的右孩子节点的父指针,再修改各自的孩子指针。

右旋逻辑:
设对节点p右旋,其目标为使节点p成为其左孩子节点的右孩子节点,操作为修改节点p和节点p的左孩子节点的父指针,再修改各自的孩子指针。

插入逻辑:

  1. 找插入位置,要插入的节点肯定为叶子节点,且设置为红色
  2. 判断其父节点颜色而做相应旋转以及变色操作

删除逻辑:

  1. 要删除的节点有左孩子节点和右孩子节点,找其直接后继节点,交换位置,待替换的节点指向后继节点的右孩子节点(如果存在的话,否则指向自己)
  2. 要删除的节点孩子节点仅有一个,替换节点即为其孩子节点
  3. 要删除的节点没有孩子节点,替换节点指向自己
  4. 如果替换节点不为删除节点,则将替换节点直接替换删除节点
  5. 根据删除节点颜色,做平衡操作
  6. 替换节点就是删除节点,修改指针引用,将其删除

图文并茂请参考https://blog.csdn.net/weixin_45685353/article/details/105912742?spm=1001.2014.3001.5502

代码实现

import java.util.*;

/**
 * 文件描述
 *
 * @author bipa
 * @date 2022/7/5
 */
public class RedBlackTree<T> {

    private TreeNode root;
    private Comparator<? super T> comparator;
    public RedBlackTree() {
    }

    public RedBlackTree(Comparator<? super T> comparator) {
        this.comparator = comparator;
    }

    class TreeNode {
        private T val;
        private TreeNode left;
        private TreeNode right;

        private TreeNode parent;
        private boolean red;

        public TreeNode(T val) {
            this.val = val;
        }
    }

    public TreeNode find(T target) {
        TreeNode p = root;
        for (; p != null; ) {
            int dir = comparator == null ? ((Comparable<? super T>) target).compareTo(p.val) : comparator.compare(target, p.val);
            if (dir < 0) {
                p = p.left;
            } else if (dir > 0) {
                p = p.right;
            } else {
                return p;
            }
        }
        return null;
    }

    public void insert(T val) {
        TreeNode p = root, pp = null;
        int dir = 0;
        for (; p != null; ) {
            pp = p;
            dir = comparator == null ? ((Comparable<? super T>) val).compareTo(p.val) : comparator.compare(val, p.val);
            if (dir < 0) {
                p = p.left;
            } else if (dir > 0) {
                p = p.right;
            } else {
                return;
            }
        }
        TreeNode node = new TreeNode(val);
        if (pp == null) {
            node.red = false;
            root = node;
            return;
        }
        if (dir < 0) {
            pp.left = node;
        } else {
            pp.right = node;
        }
        node.parent = pp;
        balanceInsert(node);
    }

    public List<T> getInnerValues() {
        List<T> list = new ArrayList<>();
        ArrayDeque<TreeNode> stack = new ArrayDeque<>();
        TreeNode p = root;
        while (p != null || !stack.isEmpty()) {
            while (p != null) {
                stack.addLast(p);
                p = p.left;
            }
            p = stack.removeLast();
            list.add(p.val);
            p = p.right;
        }
        return list;
    }

    public void remove(T target) {
        TreeNode t;
        if ((t = this.find(target)) == null) {
            return;
        }
        if (t == root && t.left == null && t.right == null) {
            root = null;
            return;
        }
        TreeNode tl = t.left, tr = t.right, replace;
        if (tl != null && tr != null) {
            TreeNode s = tr, sl;
            while ((sl = s.left) != null) {
                s = sl;
            }
            boolean c = t.red;
            t.red = s.red;
            s.red = c;
            TreeNode sr = s.right, tp = t.parent;
            if (tr == s) {
                t.parent = s;
                s.right = t;
            } else {
                TreeNode sp = s.parent;
                if ((t.parent = sp) != null) {
                    if (s == sp.left) {
                        sp.left = t;
                    } else {
                        sp.right = t;
                    }
                }
                s.right = tr;
                tr.parent = s;
            }
            t.left = null;
            if ((t.right = sr) != null) {
                sr.parent = t;
            }
            s.left = tl;
            tl.parent = s;
            if ((s.parent = tp) == null){
                root = s;
            } else if (t == tp.left) {
                tp.left = s;
            } else {
                tp.right = s;
            }
            if (sr != null) {
                replace = sr;
            } else {
                replace = t;
            }
        } else if (tl != null) {
            replace = tl;
        } else if (tr != null) {
            replace = tr;
        } else {
            replace = t;
        }
        if (replace != t) {
            TreeNode tp = replace.parent = t.parent;
            if (tp == null) {
                root = replace;
            } else if (tp.left == t) {
                tp.left = replace;
            } else {
                tp.right = replace;
            }
            t.left = t.right = t.parent = null;
        }
        if (!t.red) {
            balanceRemove(replace);
        }
        if (replace == t) {
            TreeNode tp = t.parent;
            t.parent = null;
            if (tp != null) {
                if (tp.left == t) {
                    tp.left = null;
                } else {
                    tp.right = null;
                }
            }
        }
    }

    private void balanceInsert(TreeNode t) {
        TreeNode tp, tpp, tppl, tppr;
        t.red = true;
        for (; ; ) {
            if ((tp = t.parent) == null) {
                t.red = false;
                return;
            }
            if (!tp.red || (tpp = tp.parent) == null) {
                return;
            }
            if ((tppl = tpp.left) == tp) {
                if ((tppr = tpp.right) != null && tppr.red) {
                    tppl.red = false;
                    tppr.red = false;
                    tpp.red = true;
                    t = tpp;
                } else {
                    if (t == tp.right) {
                        rotateLeft(t = tp);
                        tpp = (tp = t.parent) == null ? null : tp.parent;
                    }
                    if (tp != null) {
                        tp.red = false;
                        if (tpp != null) {
                            tpp.red = true;
                            rotateRight(tpp);
                        }
                    }
                }
            } else {
                if (tppl != null && tppl.red) {
                    tppl.red = false;
                    tp.red = false;
                    tpp.red = true;
                    t = tpp;
                } else {
                    if (t == tp.left) {
                        rotateRight(t = tp);
                        tpp = (tp = t.parent) == null ? null : tp.parent;
                    }
                    if (tp != null) {
                        tp.red = false;
                        if (tpp != null) {
                            tpp.red = true;
                            rotateLeft(tpp);
                        }
                    }
                }
            }
        }
    }

    private void balanceRemove(TreeNode t) {
        TreeNode tp, tpl, tpr;
        for (; ; ) {
            if (t == null || t == root) {
                return;
            } else if ((tp = t.parent) == null) {
                t.red = false;
                return;
            } else if (t.red) {
                t.red = false;
                return;
            } else if ((tpl = tp.left) == t) {
                if ((tpr = tp.right) != null && tpr.red) {
                    tpr.red = false;
                    tp.red = true;
                    rotateLeft(tp);
                    tpr = (tp = t.parent) == null ? null : tp.right;
                }
                if (tpr == null) {
                    t = tp;
                } else {
                    TreeNode sl = tpr.left, sr = tpr.right;
                    if ((sr == null || !sr.red) && (sl == null || !sl.red)) {
                        tpr.red = true;
                        t = tp;
                    } else {
                        if (sr == null || !sr.red) {
                            sl.red = false;
                            tpr.red = true;
                            rotateRight(tpr);
                            tpr = (tp = t.parent) == null ? null : tp.right;
                        }
                        if (tpr != null) {
                            tpr.red = tp != null && tp.red;
                            if ((sr = tpr.right) != null) {
                                sr.red = false;
                            }
                        }
                        if (tp != null) {
                            tp.red = false;
                            rotateLeft(tp);
                        }
                        t = root;
                    }
                }
            } else {
                if (tpl != null && tpl.red) {
                    tpl.red = false;
                    tp.red = true;
                    rotateRight(tp);
                    tpl = (tp = t.parent) == null ? null : tp.left;
                }
                if (tpl == null) {
                    t = tp;
                } else {
                    TreeNode sl = tpl.left, sr = tpl.right;
                    if ((sl == null || !sl.red) && (sr == null || !sr.red)) {
                        tpl.red = true;
                        t = tp;
                    } else {
                        if (sl == null || !sl.red) {
                            sr.red = false;
                            tpl.red = true;
                            rotateLeft(tpl);
                            tpl = (tp = t.parent) == null ? null : tp.left;
                        }
                        if (tpl != null) {
                            tpl.red = tp != null && tp.red;
                            if ((sl = tpl.left) != null) {
                                sl.red = false;
                            }
                        }
                        if (tp != null) {
                            tp.red = false;
                            rotateRight(tp);
                        }
                        t = root;
                    }
                }
            }
        }
    }

    private void rotateLeft(TreeNode t) {
        TreeNode tr, trl, tp;
        // 左旋,成为其右子节点的左子节点
        if (t != null && (tr = t.right) != null) {
            // 修改父指针
            if ((tp = tr.parent = t.parent) == null) {
                tr.red = false;
                root = tr;
            } else if (tp.left == t) {
                tp.left = tr;
            } else {
                tp.right = tr;
            }
            // 修改子指针
            if ((trl = t.right = tr.left) != null) {
                trl.parent = t;
            }
            // 成为其右子节点的左子节点
            tr.left = t;
            t.parent = tr;
        }
    }

    private void rotateRight(TreeNode t) {
        TreeNode tl, tlr, tp;
        // 右旋,成为其左子节点的右子节点
        if (t != null && (tl = t.left) != null) {
            // 修改父指针
            if ((tp = tl.parent = t.parent) == null) {
                tl.red = false;
                root = tl;
            } else if (tp.left == t) {
                tp.left = tl;
            } else {
                tp.right = tl;
            }
            // 修改子指针
            if ((tlr = t.left = tl.right) != null) {
                tlr.parent = t;
            }
            // 成为其左子节点的右子节点
            tl.right = t;
            t.parent = tl;
        }
    }
}

测试验证

测试类如下,


import com.bipa.tree.RedBlackTree;

import java.util.List;

/**
 * 文件描述
 *
 * @author bipa
 * @date 2022/7/5
 */
public class Main {

    public static final int LOOP_NUM = 10_000;

    public static void main(String[] args) {
        RedBlackTree<Integer> redBlackTree = new RedBlackTree<>();
        for (int i = LOOP_NUM; i > 0; i--) {
            redBlackTree.insert(i);
        }
        for (int i = LOOP_NUM; i > 0; i--) {
            // 获取红黑树中序遍历后的节点值
            List<Integer> list = redBlackTree.getInnerValues();
            System.out.println(list);

            // 验证是否升序
            for (int j = 1; j < list.size(); j++) {
                if (list.get(j-1) > list.get(j)) {
                    // 发现降序,打印fail,结束方法
                    System.out.println("fail!");
                    return;
                }
            }
            redBlackTree.remove(i);
        }
        System.out.println("succ");
    }

}

运行结果截图,
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

b17a

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

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

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

打赏作者

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

抵扣说明:

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

余额充值