2020-10-08目前代码只记录了插入过程和插入之后的恢复过程代码,删除过程代码还在整理.

package com.lsx.tree;

public class RedBlackTree {

    //红色,默认用红色
    private final int R = 0;
    //黑色
    private final int B = 1;

    private Node root = null; // 红黑树的根节点

    class Node {
        //存储数据
        int data;
        //颜色
        int color = R;
        //左
        Node left;
        //右
        Node right;
        //父节点
        Node parent;

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

    /**
     * 插入数据
     *
     * @param newNode
     */
    public void inset(Node newNode) {
        Node r = this.root;
        //新节点的父节点
        Node py = null;
        //定位新节点要插入到那个位置
        while (r != null) {
            //存储找到了位置的父节点信息
            py = r;
            if (r.data < newNode.data) {
                r = r.right;
            } else if (r.data > newNode.data) {
                r = r.left;
            } else {
                //节点值相等,替新出的节点替换掉老的节点,为啥:如果节点值是一个对象,
                // 如果使用ID来判断对象是否是同一个的时候,可能对象某个数据发生了变化。
                if (r.parent == null) {
                    this.root = newNode;
                } else {
                    if (r.parent.left == r) {
                        r.parent.left = newNode;
                    } else {
                        r.parent.right = newNode;
                    }
                    r = null;
                    newNode.parent = r.parent;
                }
                return;
            }
        }
        newNode.parent = py;
        if (py != null) {
            if (py.data < newNode.data) {
                py.right = newNode;
            } else {
                py.left = newNode;
            }
        }
        //插入的新节点默认是红色。
        //修正为一颗二叉查找树
        insertFixUp(newNode);


    }

    /**
     * 修正为一颗红黑树,节点插入正确位置之后,需要把树进行整理
     * 1.变色
     * 2.看看要怎么旋转
     *
     * @param newNode
     */
    private void insertFixUp(Node newNode) {
        Node parent, gparent;
        //诺父节点存在,并且父节点的颜色都是红色.
        //如果父节点是黑色,则不用修正
        while ((parent = newNode.parent) != null && isRed(parent)) {
            //获取祖父结点
            gparent = parent.parent;
            //检查父节点是左子树还是右子树
            if (gparent.left == parent) {
                //父节点是左子树
                // Case 1条件:叔叔节点是红色
                //        黑
                //  红(p)     红(u)
                //红
                Node uncle = gparent.right;
                //case 1
                if (uncle != null && isRed(uncle)) {
                    setBlack(uncle);
                    setBlack(parent);
                    setRead(gparent);
                    newNode = gparent;
                    continue;
                }
                //case 2
                // 此时uncle是null或者颜色是黑色(null也是黑色),且当前插入节点是右孩子,
                //旋转成插入节点在父节点的左边,形成pg ->p->newnode都是在左边
                if (parent.right == newNode) {
                    leftRotate2(parent);
                    Node tmp;
                    //旋转完成之后,把newNode的引用改成parent
                    tmp = parent;
                    parent = newNode;
                    newNode = tmp;
                }
                //case 2.1
                //叔叔全是黑色,当前节点是左孩子,进行一下右旋
                setRead(gparent);
                setBlack(parent);
                rightRotate2(gparent);
                //处理完这个之后,while会在isRed(parent)不成立而结束循环
            } else {
                //右子树
                // Case 1条件:叔叔节点是红色
                //        黑
                //  红(u)     红(p)
                //红
                Node uncle = gparent.left;
                //caes 1
                if (uncle != null && isRed(uncle)) {
                    //变色
                    setBlack(uncle);
                    setBlack(parent);
                    setRead(gparent);
                    newNode = gparent;
                    continue;
                }
                //case 2
                //此时uncle是null或者颜色是黑色(null也是黑色)
                //线程pg -p->newNode都是在右边
                if (parent.left == newNode) {
                    //旋转成插入节点在父节点的左边
                    rightRotate2(parent);
                    Node tmp;
                    //旋转完成之后,把newNode的引用改成parent
                    tmp = parent;
                    parent = newNode;
                    newNode = tmp;
                }
                //case 2.1
                setRead(gparent);
                setBlack(parent);
                rightRotate2(gparent);
                //处理完这个之后,while会在isRed(parent)不成立而结束循环
            }
        }
        //这行代码处理的是树为空的时候,插入的第一个节点
        setBlack(this.root);

    }

    /**
     * 单独写出来是方便后期如果01表示的含义不是红黑,好方便修改
     *
     * @param node
     * @return
     */
    private boolean isRed(Node node) {
        return node.color == R;
    }

    private void setRead(Node node) {
        node.color = R;
    }

    private void setBlack(Node node) {
        node.color = B;
    }

    /*
     * 对红黑树的节点(x)进行左旋转
     *
     * 左旋示意图(对节点x进行左旋):
     *      px                              px
     *     /                               /
     *    x                               y
     *   /  \      --(左旋)-.           / \                #
     *  lx   y                         x   ry
     *     /   \                       /   \
     *    ly   ry                     lx   ly
     *
     *
     */
    public void leftRotate2(Node node) {
        //获取它的右边节点
        Node y = node.right;
        //新数据,把y的左节点处理
        node.right = y.left;
        if (y.left != null) {
            y.left.parent = node;
        }
        //处理node节点的父节点
        if (node.parent.left == node) {
            //当前node节点是左边的
            node.parent.left = y;
        } else if (node.parent.right == node) {
            //右边的
            node.parent.right = y;
        } else {
            //如果父节点是空,就把新的根节点设置为树的根节点
            root = y;
        }

        //处理y节点
        y.left = node;
        node.parent = y;
    }

    /*
     * 对红黑树的节点(y)进行右旋转
     *
     * 右旋示意图(对节点y进行左旋):
     *            py                               py
     *           /                                /
     *           y                               x
     *         /  \      --(右旋)-.            /   \
     *        x   ry                          lx    y
     *       / \                                   / \
     *      lx  rx                                rx  ry
     *
     */
    public void rightRotate2(Node node) {
        Node x = node.left;
        node.left = x.right;
        if (x.right != null) {
            node.left.parent = node;
        }
        if (node.parent.left != null) {
            node.parent.left = x;
        } else if (node.parent.right != null) {
            node.parent.right = x;
        } else {
            root = x;
        }
        x.right = node;
        node.parent = x;
    }


}