数据结构之红黑树(一)

数据结构之红黑树(一)

  为什么是要使用红黑树? 

  二叉树在平均情况下的运行时间已经是对数级别,为什么还要使用红黑树?原因很简单,二叉树在最坏情况下的查找时间为线性级别,导致这种最坏情况的原因是数据的插入找特定的顺序(从大到小或者从小到大),致使数的高度过大,也就是树的不平衡,因而导致了查询效率的下降。

   因此,改变这种最差情况的查找效率就是使不平衡的树变得平衡。通过一种2-3的查找树可以使树保持平衡,但是处理的情况过于多,实现比较复杂。

  红黑树恰能通过添加节点的颜色来模拟这种2-3树。红黑树与普通二叉树的最大区别在于 ,它在原来的基础上为每个节点设立了颜色。红黑树应该满足如下特性:
    1)红色节点均为左节点
    2)红色节点不能和红色节点相连接
    3)该树是完美黑色平衡,即任意空链接到根节点所经历的黑色节点的数量相同。
  这样以来,仅仅改变树的构造方法,如添加节点和删除节点,而查找以及其他方法均与普通二叉查找树相同。
  不过,红黑树的左旋、右旋和颜色变换等相关方法需要认证理解。

  

public class RedBlackBST<Key extends Comparable<Key>,Value> {
    private Node root;//红黑树的根节点
    
    private static final boolean RED = true;
    private static final boolean BLACK = false;
    
    private class Node {
        Key key;
        Value value;
        Node left;
        Node right;
        boolean color;//为没个节点设置颜色
        public Node(Key key, Value value, boolean color) {
            super();
            this.key = key;
            this.value = value;

            this.color = color;
        }
    }
    
    private boolean isRed(Node node) {
        if(node == null) {
            return false;
        }
        
        return node.color;
    }
    
    /**
     * 添加节点
     * @param key
     * @param value
     */
    public void put(Key key,Value value) {
        root = put(root,key,value);
        root.color = BLACK;
    }

    /**
     * 向以h为根节点的子树中添加元素

     */
    private Node put(Node h, Key key, Value value) {
        if(h == null) {//递归到树的底部,创建新新节点,返回给上层递归函数,赋值给父节点
            return new Node(key,value,RED);
        }
        //添加元素与二叉树添加元素相同
        int cmp = key.compareTo(h.key);
        if(cmp < 0) {
            h.left = put(h.left,key,value);
        }else if(cmp > 0) {
            h.right = put(h.right,key,value);
        }else {
            h.value = value;
        }
        
        /**
         * 二叉树的变换
         *     这是红黑树区别于二叉树的地方,添加完元素,对数进行变换。
         *         对于不满足红黑树要求的地方进行变换。
         *             主要有以下三种情况,顺序不能改变
         */
        if(isRed(h.right) && !isRed(h.left)) {//情况1:右红左不红,右旋转
            h = rotateLeft(h);
        }
        if(isRed(h.left) && isRed(h.left.left)) {//情况2:左红,左左红,先右旋转,旋转完后满足情况3,进行颜色变换
            h = rotateRight(h);
        }
        
        if(isRed(h.left) && isRed(h.right)) {//情况3:右红左红,变换颜色
            flipColor(h);
        }
        
        return h;
    }

    /**
     *变化颜色
     * @param h
     */
    private void flipColor(Node h) {
        h.color = RED;//父节点变为红色
        h.left.color = BLACK;//子节点变为黑色
        h.right.color = BLACK;//子节点变为黑色
    }

    /**
     * 右旋转
     * @param h
     * @return
     */
    private Node rotateRight(Node h) {
        Node x = h.left;
        h.left = x.right;
        x.right = h;
        x.color = h.color;
        h.color = RED;
        return x;
    }

    /**
     * 左旋转
     * @param h
     * @return
     */
    private Node rotateLeft(Node h) {
        Node x = h.right;
        h.right = x.left;
        x.left = h;
        x.color = h.color;
        h.color = RED;
        return h;
    }
    
}

  对于树的删除操作,在后续博文中介绍。

原文地址:https://www.cnblogs.com/gdy1993/p/9332641.html