红黑树的添加与删除

public class readBlackTree {
    public static void main(String[] args) {
        //初始化对象
        RBTree rbTree = new RBTree();
        //测试的数据
        int[] array = {20, 25, 45, 748, 1, 13, 14};
        //通过循环向红黑树中添加元素
        for (int i = 0; i < array.length; i++) {
            rbTree.insert(array[i]);
        }
        System.out.println("前序遍历是:");
        System.out.println("红色表示false,黑色表示true");
        rbTree.preOrder();
     /*   System.out.println("中序遍历是:");
        rbTree.inOrder();*/
        rbTree.delete(25);
        System.out.println("删除后");
        rbTree.preOrder();
    }
}

//定义树
class RBTree {
    Node root;
    //进行常量设置 false表示red
    //true表示black
    private final boolean Red = false;
    private final boolean Black = true;

    //通过二分查找一个新节点需要插入的父节点位置
    public Node query(int value) {
        Node tmp = root;
        while (tmp != null) {
            if (tmp.getValue() == value) {
                System.out.println("该节点已存在请重新输入!");
                return tmp;
                //如果插入的值小于节点的值则向左遍历
            } else if (tmp.getValue() > value) {
                tmp = tmp.getLeft();
                //大于则向右
            } else {
                tmp = tmp.getRight();
            }
        }
        return null;
    }

    //添加结点
    public void insert(int value) {
        //创建当前值为value的红色节点
        Node node = new Node(value);
        //如果根节点为空则将该节点设为根节点
        if (root == null) {
            root = node;
            root.setColor(Black);
            return;
        }
        //设置父节点和子节点
        Node parent = root;
        Node son = null;
        //判断在根节点的左子树还是右子树
        if (value <= parent.getValue()) {
            son = parent.getLeft();
        } else {
            son = parent.getRight();
        }
        //通过while循环 交互赋值 找寻插入的位置
        while (son != null) {
            parent = son;
            if (value <= parent.getValue()) {
                son = parent.getLeft();
            } else {
                son = parent.getRight();
            }
        }
        //while循环已经推出说明此时的son为空,达到了叶子结点处
        if (value <= parent.getValue()) {
            parent.setLeft(node);
        } else {
            parent.setRight(node);
        }
        //将当前的节点父节点设置为parent保证正确衔接
        node.setParent(parent);
        //成功插入后对该节点进行红黑树性质的判断,修改(看是否违反了红黑树的五大性质,满足则进行修改)
        insertFix(node);
    }

    public void delete(int key) {
        Node node;
        if ((node = find(key, this.root)) != null) {
            System.out.println("找到啦!正在删除。。。。。。");
            delete(node);
        } else {
            System.out.println("没找到该节点奥!!!!!!!");
            return;
        }
    }

    //对添加后的结点进行修改
    public void insertFix(Node node) {
        Node father, grandFather;
        //只要父节点不为空且为红色
        while ((father = node.getParent()) != null && father.getColor() == Red) {
            //找到其祖父节点
            grandFather = father.getParent();
            //如果父亲节点在左那么叔叔节点就在右
            if (grandFather.getLeft() == father) {
                Node uncle = grandFather.getRight();
                //情况1如果叔叔节点为红,则改变祖父节点为红,以及父亲节点和叔叔节点为黑
                //修改节点并将祖父节点设置为当前节点进行递归
                if (uncle != null && uncle.getColor() == Red) {
                    father.setColor(Black);
                    uncle.setColor(Black);
                    grandFather.setColor(Red);
                    node = grandFather;
                    continue;
                }
                //情况2:如果叔叔节点是黑色且如果当前节点与父节点祖父节点是之字形
                //就先对进行左旋形成一字形
                if (node == father.getRight()) {
                    leftRotate(father);
                    Node tmp = node;
                    node = father;
                    father = tmp;
                }
                //情况3:如果叔叔节点是黑色且如果当前节点与父节点祖父结点是一字形
                father.setColor(Black);
                grandFather.setColor(Red);
                rightRotate(grandFather);
            } else {
                //如果父节点在右边,叔叔节点就在左侧
                Node uncle = grandFather.getLeft();
                //如果叔叔节点是红色(与父节点是同一个颜色)则进行循环染色操作
                if (uncle != null && uncle.getColor() == Red) {
                    father.setColor(Black);
                    uncle.setColor(Black);
                    grandFather.setColor(Red);
                    node = grandFather;
                    continue;
                }
                //与上面相反
                if (node == father.getLeft()) {
                    rightRotate(father);
                    Node tmp = node;
                    node = father;
                    father = tmp;
                }
                //相反
                father.setColor(Black);
                grandFather.setColor(Red);
                leftRotate(grandFather);
            }
        }
        //不管怎样修改,修改到最后根节点都是要置成黑色保证红黑树的性质
        root.setColor(Black);
    }

    //删除节点
    public void delete(Node node) {
        //定义孩子节点和父节点
        Node child, parent;
        boolean color;
        //如果删除的节点有左右子树
        if ((node.getLeft() != null) && (node.getRight() != null)) {
            //辅助节点
            Node replace = node;
            //通过while循环找到删除节点的右子树中最小值替换
            replace = replace.getRight();
            while (replace.getLeft() != null) {
                replace = replace.getLeft();
            }
            //如果父节点不为空表示不是根节点(只有根节点不存在父节点)
            if (node.getParent() != null) {
                //如果删除节点是该节点的父节点的左节点则将replace替换到父节点的左节点中
                if (node.getParent().getLeft() == node) {
                    node.getParent().setLeft(replace);
                } else {//否则替换到右节点中
                    node.getParent().setRight(replace);
                }
            } else {//如果是根节点则将根节点直接设置为找的的右子树中最小值
                this.root = replace;
            }
            //如果replace节点有右孩子,则将孩子赋值给replace的父节点的左子节点
            child = replace.getRight();
            parent = replace.getParent();
            color = replace.getColor();
            //如果替换的节点的父节点就是删除的节点则直接替换省去对右节点的修改
            if (parent == node) {
                parent = replace;
            } else {
                //否则对替换的子节点进行链接还包括对替换删除节点的右节点的修改
                if (child != null) {
                    child.setParent(parent);
                    parent.setLeft(child);
                }
                //如果替换的节点没有右孩子,需要将替换节点的父节点的左孩子置空
                parent.setLeft(null);
                //将删除的节点用替换的节点进行替换
                //替换的右节点修改
                replace.setRight(node.getRight());
                node.getRight().setParent(replace);
            }
            //无论替换的节点的父节点是不是删除的节点都需要对父节点和左子节点进行修改    //因为这句话replace = node.getRight();
            replace.setParent(node.getParent());
            replace.setColor(node.getColor());
            replace.setLeft(node.getLeft());
            node.getLeft().setParent(replace);
            //这是对之前color赋值后的判断
            //如果替换的节点是黑色就要进行修复(因为黑色节点的替换会影响到红黑树的平衡)
            if (color == Black) {
                removeFixUp(child, parent);
            }
            //将删除的节点进行置空
            node = null;
            return;
        }
        // 如果该节点的左子树不为空则直接用左子节点替代
        if (node.getLeft() != null) {
            child = node.getLeft();
        } else {//如果右子树不为空,  或者删除的是叶子结点
            child = node.getRight();
        }
        parent = node.getParent();
        color = node.getColor();
        if (child != null) {
            child.setParent(parent);
        }
        //如果不是根节点则直接赋值
        if (parent != null) {
            if (parent.getLeft() == node) {
                parent.setLeft(child);
            } else {
                parent.setRight(child);
            }
        } else {//如果是根节点,直接将node节点的孩子设置为根节点
            this.root = child;
        }
        if (color == Black) {
            removeFixUp(child, parent);
        }
        node = null;
    }


    /**
     * 1 节点是红色或黑色。
     * 2 根节点是黑色。
     * 3 每个叶节点(这里的叶节点是指NULL节点)是黑色的。
     * 4 从每个叶子到根的所有路径上不能有两个连续的红色节点。
     * 5 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
     * 对删除后的节点进行平衡修复
     *   因为我们删除一个非叶子结点,实际上删除的是替换节点,如果替换节点的颜色是黑色即破坏了红黑树的平衡(平衡条件5),需要进行修复
     *   修复传入的是替换节点的子节点和替换节点的父节点,这里我的理解是:替换节点的删除,会让替换节点的右子结点替代上替换节点的颜色,
     *   也就是说替换节点的子节点的颜色为替换节点的颜色,如果该颜色为黑或者该节点是空且父节点没有达到root节点,会一直进行while循环
     *   进行修复操作,通过while循环里的方法进行修复成满足红黑树的5大规范
     *
     * @param node   表示替换节点的子节点(应为替换的节点保持和删除节点相同颜色,不会影响平衡)替换的子节点会导致平衡
     * @param parent 表示替换节点的父节点
     */
    public void removeFixUp(Node node, Node parent) {
        //定义兄弟结点
        Node other;
        //只要删除的节点是黑色,或者该节点不是根节点就一直循环
        while ((node == null || node.getColor() == Black) && (node != this.root)) {
            if (parent.getLeft() == node) {
                other = parent.getRight();
                if (other.getColor() == Red) {
                    //情况一:node结点的兄弟结点other是红色
                    //采取措施:将other与parent交换颜色并左旋
                    other.setColor(Black);
                    parent.setColor(Red);
                    leftRotate(parent);
                    //将兄弟结点重新赋值
                    other = parent.getRight();
                }
                //情况二:node节点的兄弟结点是黑色,且两个孩子都是黑色
                if ((other.getColor() == Black || other == null) && (other.getLeft() == null || other.getLeft().getColor() == Black) && (other.getRight() == null || other.getRight().getColor() == Black)) {
                    other.setColor(Red);
                    node = parent;
                    parent = node.getParent();
                } else {
                  //情况三:node结点的兄弟结点为黑色,且兄弟结点的左子结点为红色,右子结点是黑色
                    if ((other.getColor() == Black || other == null) && (other.getRight() == null || other.getRight().getColor() == Black) && other.getLeft().getColor() == Red) {
                        other.getLeft().setColor(Black);
                        other.setColor(Red);
                        rightRotate(other);
                        other = parent.getRight();
                    }
                    情况四:node结点的兄弟结点为黑色,并且兄弟结点的右节点是红色的左子结点是任意颜色
                    other.setColor(parent.getColor());
                    parent.setColor(Black);
                    other.getRight().setColor(Black);
                    leftRotate(parent);
                    node = this.root;
                    break;

                }
            } else {//如果删除的节点在右边
                other = parent.getLeft();
                if (other.getColor() == Red) {
                    //情况一:node结点的兄弟结点other是红色
                    //采取措施:将other与parent交换颜色并左旋
                    other.setColor(Black);
                    parent.setColor(Red);
                    rightRotate(parent);
                    other = node.getParent().getLeft();
                }
                //情况二:node节点的兄弟结点是黑色,且两个孩子都是黑色
                if ((other.getColor() == Black || other == null) && (other.getLeft() == null || other.getLeft().getColor() == Black) && (other.getRight() == null || other.getRight().getColor() == Black)) {
                    other.setColor(Red);
                    node = parent;
                    parent = node.getParent();
                } else {
                    //情况三:node结点的兄弟结点为黑色,并且兄弟结点的左节点是红色的右子结点是黑色
                    if ((other.getColor() == Black || other == null) && other.getColor() == Black && other.getLeft().getColor() == Red && (other.getRight().getColor() == Black || other.getRight() == null)) {
                        other.getRight().setColor(Black);
                        other.setColor(Red);
                        leftRotate(other);
                        other = parent.getLeft();
                    }
                    //情况四:node结点的兄弟结点为黑色,且兄弟结点的右子结点是红色的左子结点是任意颜色
                    other.setColor(parent.getColor());
                    parent.setColor(Black);
                    other.getLeft().setColor(Black);
                    rightRotate(parent);
                    node = this.root;
                    break;
                }
            }
        }
        if (node != null) {
            node.setColor(Black);
        }
    }

    //左旋转
    public void leftRotate(Node node) {
        Node right = node.getRight();
        node.setRight(right.getLeft());
        if (right.getLeft() != null) {
            right.getLeft().setParent(node);
        }
        right.setParent(node.getParent());
        if (node.getParent() == null) {
            root = right;
        } else {
            if (node.getParent().getLeft() == node) {
                node.getParent().setLeft(right);
            } else {
                node.getParent().setRight(right);
            }
        }
        right.setLeft(node);
        node.setParent(right);
    }

    //右旋转

    /**
     * 传入需要旋转的根节点(最上面的节点)
     */
    public void rightRotate(Node node) {
        Node left = node.getLeft();
        node.setLeft(left.getRight());
        if (left.getRight() != null) {
            left.getRight().setParent(node);
        }
        left.setParent(node.getParent());
        if (node.getParent() == null) {
            root = left;
        } else {
            if (node == node.getParent().getRight()) {
                node.getParent().setRight(left);
            } else {
                node.getParent().setLeft(left);
            }
        }
        left.setRight(node);
        node.setParent(left);
    }

    //前序遍历
    public void preOrder() {
        preOrder(root);
    }

    private void preOrder(Node node) {
        if (node == null) {
            return;
        }
        System.out.println(node);
        preOrder(node.getLeft());
        preOrder(node.getRight());
    }

    //中序遍历
    public void inOrder() {
        inOrder(root);
    }

    private void inOrder(Node node) {
        if (node == null) {
            return;
        }
        inOrder(node.getLeft());
        System.out.println(node);
        inOrder(node.getRight());
    }

    //后序遍历
    public void postOrder() {
        postOrder(root);
    }

    private void postOrder(Node node) {
        if (node == null) {
            return;
        }
        postOrder(node.getLeft());
        postOrder(node.getRight());
        System.out.println(node);
    }

    public Node find(int value, Node node) {
        if (node != null) {
            if (value < node.getValue()) {
                return find(value, node.getLeft());
            } else if (value > node.getValue()) {
                return find(value, node.getRight());
            } else {
                return node;
            }
        }
        return null;
    }
}

//定义节点
class Node {
    private final boolean Red = false;
    private final boolean Black = true;
    private int value;
    private Node left;
    private Node right;
    private boolean color;
    private Node Parent;

    public Node(int value, boolean color) {
        this.value = value;
        this.color = Red;
    }

    public Node(int value) {
        this.value = value;
    }

    //由于删除叶子结点后不能添加值为null的黑节点所以利用结点0并且黑色来代替(集合可以)
    public void nullNode(int value, boolean color) {
        this.value = 0;
        this.color = Black;
    }


    public Node(Integer integer, boolean color) {
    }

    public int getValue() {
        return value;
    }

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

    public Node getLeft() {
        return left;
    }

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

    public Node getRight() {
        return right;
    }

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

    public boolean getColor() {
        return color;
    }

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

    public Node getParent() {
        return Parent;
    }

    public void setParent(Node parent) {
        Parent = parent;
    }

    @Override
    public String toString() {
        return "Node{" +
                "value=" + value +
                ", color=" + color +
                '}';
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值