码迷,mamicode.com
首页 > 其他好文 > 详细

红黑树代码实现

时间:2020-01-06 00:20:07      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:main   span   ble   tostring   div   --   不用   final   dede   

public class RBNodeDemo {
    public static void main(String[] args) {
        RBNode<Integer> node1 = new RBNode<>(1);
        RBNode<Integer> node2 = new RBNode<>(2);
        RBNode<Integer> node3 = new RBNode<>(3);
        RBNode<Integer> node4 = new RBNode<>(4);
        node1.insert(node2);
        node1.insert(node3);
        node1.insert(node4);

        RBNode<Integer> root = node1.root();
        System.out.println(root);


    }
}

/**
 * 红黑树
 */
class RBNode<T extends Comparable<T>> {
    boolean red = true;
    T data;
    RBNode<T> left;
    RBNode<T> right;
    RBNode<T> parent;

    public RBNode(boolean red, T data, RBNode<T> left, RBNode<T> right, RBNode<T> parent) {
        this.red = red;
        this.data = data;
        this.left = left;
        this.right = right;
        this.parent = parent;
    }


    public RBNode(T data) {
        this.data = data;
    }

    /**
     * 返回当前节点的root节点
     * 该方法的时间复杂度应该是O(n)
     *
     * @return
     */
    final RBNode<T> root() {
        for (RBNode<T> root = this, p; ; ) {
            if ((p = root.parent) == null) {  // 如果当前节点的父节点为空,那说明当前节点就是根节点,直接返回当前节点
                return root;
            }
            root = p;  // 当前节点变成原节点的父节点
        }
    }


    /*
     * 左旋示意图:对节点x进行左旋
     *     p                       p
     *    /                       /
     *   x                       y
     *  / \                     /      *lx   y      ----->       x   ry
     *    / \                 /       *  ly   ry              lx   ly
     * 左旋做了三件事:
     * 1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时)
     * 2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右)
     * 3. 将y的左子节点设为x,将x的父节点设为y
     * 注意: 在移动节点位置时,不要忘了双向指定
     */
    public void rotateLeft(RBNode<T> x) {
        RBNode<T> y, ly, p;
        if (x != null && (y = x.right) != null) {
            // 1.  将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时)
            // 做非空的判断的目的是: 如果y没有左子节点,都不用挂到x的右子节点上了
            if ((ly = x.right = y.left) != null) {
                ly.parent = x;
            }

            //2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右)
            if ((p = y.parent = x.parent) == null) {
                y.parent = null;// y成了根节点,可以直接置为黑色
                y.red = false;
            } else if (p.left == x) {  // 如果x是p的左子节点,那么旋转后y也是p的左子节点
                p.left = y;  // 将y置为p的左子节点
            } else {     // x是p右子节点,那么旋转后y也是p的右子节点
                p.right = y;  // 将y置为p的右子节点
            }

            // 3. 将y的左子节点设为x,将x的父节点设为y
            y.left = x;
            x.parent = y;
        }
    }


    /*
     * 右旋示意图:对节点y进行右旋
     *        p                   p
     *       /                   /
     *      y                   x
     *     / \                 /      *    x   ry   ----->    lx   y
     *   / \                     /      * lx   rx                 rx   ry
     * 右旋做了三件事:
     * 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时)
     * 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右)
     * 3. 将x的右子节点设为y,将y的父节点设为x
     */
    public void rotateRight(RBNode<T> y) {
        RBNode<T> x, rx, p;
        if (y != null && (x = y.left) != null) {

            // 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时)
            if ((rx = y.left = x.right) != null)
                rx.parent = y;

            // 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右)
            // 2. 简而言之, 就是挂左挂右的问题
            if ((p = x.parent = y.parent) == null) {  // 判断父是否为null
                x.parent = null;
                x.red = false;  // 这句代码放这儿好吗?
            } else if (p.right == y) {  // 判断是左...
                p.right = x;
            } else {   // 否则就是右
                p.left = x;
            }

            // 3. 将x的右子节点设为y,将y的父节点设为x
            x.right = y;
            y.parent = x;
        }
    }

    /**
     * 从root节点开始遍历比较
     *
     * @param x
     */
    public void insert(RBNode<T> x) {
        RBNode<T> root = root();
        insert(root, x);
        // todo 重平衡...
        balanceInsertion(root, x);
    }

    /**
     * 有如下多种情况:
     * 1. 如果原树为空, root == x, 只需要把root置为黑色即可
     * 2. 如果父节点是黑色,添加上去即可,啥都不需要做
     * 3. 下面三种情况较为复杂,需要变色或者旋转
     * (1).插入节点的父节点和其叔叔节点(祖父节点的另一个子节点)均为红色的;
     * (2).插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的右子节点;
     * (3).插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的左子节点。
     *
     * @param root
     * @param x    8 ----> 11---->14----->13----->1---->2-----> 5----->9  ----> x= 4
     */
    private void balanceInsertion(RBNode<T> root, RBNode<T> x) {

    }

    private void insert(RBNode<T> root, RBNode<T> x) {
        if (root.data.compareTo(x.data) < 0) {
            if (root.right == null) {
                root.right = x;
                x.parent = root;
            } else {
                insert(root.right, x);
            }
        } else {
            if (root.left == null) {
                root.left = x;
                x.parent = root;
            } else {
                insert(root.left, x);
            }
        }
    }

    @Override
    public String toString() {
        return "red=" + (red ? "Red" : "Black") + ", data=" + data;
    }
}

 

未完待续中......

红黑树代码实现

标签:main   span   ble   tostring   div   --   不用   final   dede   

原文地址:https://www.cnblogs.com/z-qinfeng/p/12154339.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!