java红黑树实现

一个简单的红黑树小案例分析

在这里插入图片描述

java红黑树简单实现

package com.yusys.tree;

import java.util.Objects;

/**
 * ①创建RBTree,定义颜色
 * ②创建RBNode
 * ③辅助方法定义:parentOf(node),isRed(node),setRed(node),setBlack(node),inOrderPrint(RBNode tree)
 * ④左旋方法定义:leftRotate(node)
 * ⑤右旋方法定义:rightRotate(node)
 * ⑥公开插入接口方法定义:insert(K key, V value);
 * ⑦内部插入接口方法定义:insert(RBNode node);
 * ⑧修正插入导致红黑树失衡的方法定义:insertFIxUp(RBNode node);
 * ⑨测试红黑树正确性
 *
 *
 * @Author zhouxz
 * @Date 2020-8-14
 */
public class RBTree<K extends Comparable<K>,V> {

    //红黑树的根节点
    private RBNode root;

    private static final Boolean RED = true;

    private static final Boolean BLACK = false;

    public RBNode getRoot() {
        return root;
    }

    /**
     * node节点是否为红色
     * @return boolean true 表示是红色  false 表示不是红色
     */
    private boolean isRed(RBNode node){
        if (Objects.nonNull(node)) {
            return node.color==RED;
        }
        return false;
    }

    /**
     * node节点是否为黑色
     * @return boolean
     */
    private boolean isBlack(RBNode node){
        if (Objects.nonNull(node)) {
            return node.color==BLACK;
        }
        return false;
    }

    /**
     * 设置节点为红色
     */
    private void setRed(RBNode node){
        if (Objects.nonNull(node)) {
            node.setColor(RED);
        }
    }

    /**
     * 设置节点为黑色
     */
    private void setBlack(RBNode node){
        if (Objects.nonNull(node)) {
            node.setColor(BLACK);
        }
    }

    /**
     * 获取当前节点的父节点
     */
    private RBNode parentOf(RBNode node){
        if (Objects.nonNull(node)) {
            return node.parent;
        }
        return null;
    }

    /**
     * 中序打印,可以将二叉查找树有顺序的打印出来
     */
    public void inOrderPrint(){
        if (Objects.nonNull(this.root)) {
            inOrderPrint(this.root);
        }
    }

    /**
     * 中序遍历当前树 左 根 右
     * @param node
     */
    private void inOrderPrint(RBNode node) {

        if (Objects.nonNull(node)) {
            inOrderPrint(node.left);
            System.out.println("key: " + node.getKey() + " value: " + node.getValue());
            inOrderPrint(node.right);
        }
    }

    /**
     * 左旋方法
     * 左旋示意图:左旋x节点
     *   p                         p
     *   |                         |
     *   x                         y
     *  / \         ---->         / \
     * lx   y                    x   ry
     *     / \                  /  \
     *    ly  ry               lx   ly
     * <p>
     * <p>
     * 1.将旋转节点的右子节点的左子节点--->旋转节点的右子节点,将旋转节点的右子节点--->旋转节点的右子节点的左子节点
     * 2.将旋转节点的右子节点--->旋转节点的父节点, 旋转节点的父节点设置为旋转节点的右子节点
     * 3.旋转节点的右子节点的父节点--->旋转节点的父节点,旋转节点的父节点--->旋转节点的右子节点的(位置未知)子节点
     */
    private void leftRotate(RBNode node) {

        if (Objects.nonNull(node)) {
            RBNode parent = node.parent;
            RBNode right = node.right;
            //1. 依据上图 更新y的左子节点为x的右子节点,若y的左子节点不为空,则更新y的左子节点的父节点为x
            node.right = right.left;
            if (Objects.nonNull(right.left)) {
                right.left.parent = node;
            }

            //2. 依据上图若是x的父节点不为null,则说明x不是根节点
            // 更新y的父节点为x的父节点, 判断x是parent的左子节点还是右子节点,根据x的位置更新y的位置
            right.parent = parent;
            if(Objects.nonNull(parent)){
                if (parent.left==node) {
                    parent.left = right;
                }else{
                    parent.right = right;
                }
            }else {
                //说明x为根节点  更新y为根节点
                this.root = right;
                this.root.parent = null; //确保根节点没有父节点
            }

            //3.更新x与y的关系
            node.parent = right;
            right.left = node;
        }
    }

    /**
     * 右旋方法
     * 右旋示意图:右旋y节点
     *
     *    p                       p
     *    |                       |
     *    y                       x
     *   / \          ---->      / \
     *  x   ry                  lx  y
     * / \                         / \
     *lx  ly                      ly  ry
     *
     * 右旋都做了几件事?
     * 1.将x的右子节点 赋值 给了 y 的左子节点,并且更新x的右子节点的父节点为 y
     * 2.将y的父节点(不为空时)指向x,更新x的父节点为y的父节点
     * 3.将x的右子节点指向y,更新y的父节点为x
     */
    private void rightRotate(RBNode y){

        if (Objects.nonNull(y)) {
            RBNode x = y.left;

            //1.
            y.left = x.right;
            if (Objects.nonNull(x.right)) {
                x.right.parent = y;
            }

            //2.
            x.parent = y.parent;
            if (Objects.nonNull(y.parent)) {
                if (y.parent.left==y){
                    y.parent.left = x;
                }else{
                    y.parent.right = x;
                }

            }else {
                this.root = x;
                this.root.parent =null;
            }
            //3.
            x.right = y;
            y.parent = x;
        }
    }

    /**
     * 公开的插入接口
     * @param key 键
     * @param value 值
     */
    public void insert(K key, V value){
        RBNode<K, V> node = new RBNode<>(key, value, RED);
        insert(node);
    }

    /**
     * 内部插入接口定义
     */
    private void insert(RBNode node){
        //找到插入位置
        RBNode parent = null;
        RBNode r = this.root;

        while (r != null) {
            parent = r;
            int com = node.key.compareTo(parent.key);
            //说明插入节点在右边
            if (com > 0) {
                r = parent.right;
            }else if (com==0){  //相等说明当前节点找到了相同的key 只需要替换值
                parent.setValue(node.value);
                return;
            }else { //说明插入节点在左边
                r = parent.left;
            }
        }

        node.parent = parent;

        if (parent != null) {
            if (node.key.compareTo(parent.key)>0) {
                parent.right = node;
            }else{
                parent.left = node;
            }
        }else {
            this.root = node;
        }
        //插入之后需要进行修复红黑树,让红黑树再次平衡。
        insertFixUp(node);
    }

    /**
     * 插入后修复红黑树平衡的方法
     *     |---情景1:红黑树为空树   不需要处理
     *     |---情景2:插入节点的key已经存在   不需要处理
     *     |---情景3:插入节点的父节点为黑色  不需要处理,插入节点为红色节点,不会破坏红黑树的规则
     *
     *     情景4 需要咱们去处理
     *     |---情景4:插入节点的父节点为红色
     *          |---情景4.1:叔叔节点存在,并且为红色(父-叔 双红)
     *          |---情景4.2:叔叔节点不存在,或者为黑色,父节点为爷爷节点的左子树
     *               |---情景4.2.1:插入节点为其父节点的左子节点(LL情况)
     *               |---情景4.2.2:插入节点为其父节点的右子节点(LR情况)
     *          |---情景4.3:叔叔节点不存在,或者为黑色,父节点为爷爷节点的右子树
     *               |---情景4.3.1:插入节点为其父节点的右子节点(RR情况)
     *               |---情景4.3.2:插入节点为其父节点的左子节点(RL情况)
     *
     */
    private void insertFixUp(RBNode node) {
        //设置根节点的颜色为黑色
        this.root.setColor(BLACK);

        RBNode parent = parentOf(node);
        RBNode gParent = parentOf(parent);

        //情景4:插入节点的父节点为红色
        if (Objects.nonNull(parent) && isRed(parent)) {
            //如果父节点为红色,则一定存在祖父节点,因为根节点为黑色,所以父节点存在上层节点

            // 若果父节点为祖父节点的左子节点  LL双红
            if (gParent.left == parent) {
                //LL双红 且存在叔叔节点 且叔叔节点为红色
                //情景4.1:叔叔节点存在,并且为红色(父-叔 双红)
                RBNode uncle = gParent.right;
                if (Objects.nonNull(uncle) && isRed(uncle)) {
                    setBlack(uncle);
                    setBlack(parent);
                    setRed(gParent);
                    insertFixUp(gParent);
                    return;
                }

                //如果叔叔节点不存在 或者  叔叔节点为黑色
                if (Objects.isNull(uncle) || isBlack(uncle)) {
                    //判断插入节点在父节点的左还是右

                    //右子节点
                    if (parent.right==node) {

                        leftRotate(parent);
                        insertFixUp(parent);
                        return;
                    }

                    //左子节点
                    if (parent.left==node) {
                        setRed(gParent);
                        setBlack(parent);
                        rightRotate(gParent);
                    }

                }
            }
            //父节点为祖父节点的右子节点
            else {
                RBNode uncle = gParent.left;

                //叔叔节点存在 且为红色
                if (Objects.nonNull(uncle) && isRed(uncle)) {
                    setBlack(parent);
                    setBlack(uncle);
                    setRed(gParent);
                    insertFixUp(gParent);
                    return;
                }

                //叔叔节点不存在 或者为空
                if (Objects.isNull(uncle) || isBlack(uncle)){

                    //判断插入节点是父节点的左 还是 右

                    //插入节点是父节点的右子节点
                    if (parent.right==node) {
                        setRed(gParent);
                        setBlack(parent);
                        leftRotate(gParent);
                    }

                    if (parent.left == node) {
                        rightRotate(parent);
                        insertFixUp(parent);
                        return;
                    }

                }
            }

        }
    }


    /**
     * 红黑树Node节点
     * @param <K>
     * @param <V>
     */
    static class RBNode<K extends Comparable<K>,V> {
        private K key;
        private V value;
        private RBNode parent;
        private RBNode left;
        private RBNode right;
        private boolean color;

        public RBNode() {
        }

        public RBNode(K key, V value, boolean color) {
            this.key = key;
            this.value = value;
            this.color = color;
        }

        public RBNode(K key, V value, RBNode parent, RBNode left, RBNode right, boolean color) {
            this.key = key;
            this.value = value;
            this.parent = parent;
            this.left = left;
            this.right = right;
            this.color = color;
        }

        public K getKey() {
            return key;
        }

        public void setKey(K key) {
            this.key = key;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public RBNode getParent() {
            return parent;
        }

        public void setParent(RBNode parent) {
            this.parent = parent;
        }

        public RBNode getLeft() {
            return left;
        }

        public void setLeft(RBNode left) {
            this.left = left;
        }

        public RBNode getRight() {
            return right;
        }

        public void setRight(RBNode right) {
            this.right = right;
        }

        public boolean isColor() {
            return color;
        }

        public void setColor(boolean color) {
            this.color = color;
        }
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值