java中treemap简介-红黑树实现

http://blog.csdn.net/chenssy/article/details/26668941

左旋操作:

红黑树左旋操作

 private void rotateLeft(Entry<K,V> p) {
        if (p != null) {
            Entry<K,V> r = p.right;
            p.right = r.left;
            if (r.left != null)
                r.left.parent = p;
            r.parent = p.parent;
            if (p.parent == null)
                root = r;
            else if (p.parent.left == p)
                p.parent.left = r;
            else
                p.parent.right = r;
            r.left = p;
            p.parent = r;
        }
    }

红黑树右旋操作

 /** From CLR */
    private void rotateRight(Entry<K,V> p) {
        if (p != null) {
            Entry<K,V> l = p.left;
            p.left = l.right;
            if (l.right != null) l.right.parent = p;
            l.parent = p.parent;
            if (p.parent == null)
                root = l;
            else if (p.parent.right == p)
                p.parent.right = l;
            else p.parent.left = l;
            l.right = p;
            p.parent = l;
        }
    }

 TreeMap源码的put操作

public V put(K key, V value) {
           //用t表示二叉树的当前节点
            Entry<K,V> t = root;
            //t为null表示一个空树,即TreeMap中没有任何元素,直接插入
            if (t == null) {
                //比较key值,个人觉得这句代码没有任何意义,空树还需要比较、排序?
                compare(key, key); // type (and possibly null) check
                //将新的key-value键值对创建为一个Entry节点,并将该节点赋予给root
                root = new Entry<>(key, value, null);
                //容器的size = 1,表示TreeMap集合中存在一个元素
                size = 1;
                //修改次数 + 1
                modCount++;
                return null;
            }
            int cmp;     //cmp表示key排序的返回结果
            Entry<K,V> parent;   //父节点
            // split comparator and comparable paths
            Comparator<? super K> cpr = comparator;    //指定的排序算法
            //如果cpr不为空,则采用既定的排序算法进行创建TreeMap集合
            if (cpr != null) {
                do {
                    parent = t;      //parent指向上次循环后的t
                    //比较新增节点的key和当前节点key的大小
                    cmp = cpr.compare(key, t.key);
                    //cmp返回值小于0,表示新增节点的key小于当前节点的key,则以当前节点的左子节点作为新的当前节点
                    if (cmp < 0)
                        t = t.left;
                    //cmp返回值大于0,表示新增节点的key大于当前节点的key,则以当前节点的右子节点作为新的当前节点
                    else if (cmp > 0)
                        t = t.right;
                    //cmp返回值等于0,表示两个key值相等,则新值覆盖旧值,并返回新值
                    else
                        return t.setValue(value);
                } while (t != null);
            }
            //如果cpr为空,则采用默认的排序算法进行创建TreeMap集合
            else {
                if (key == null)     //key值为空抛出异常
                    throw new NullPointerException();
                /* 下面处理过程和上面一样 */
                Comparable<? super K> k = (Comparable<? super K>) key;
                do {
                    parent = t;
                    cmp = k.compareTo(t.key);
                    if (cmp < 0)
                        t = t.left;
                    else if (cmp > 0)
                        t = t.right;
                    else
                        return t.setValue(value);
                } while (t != null);
            }
            //将新增节点当做parent的子节点
            Entry<K,V> e = new Entry<>(key, value, parent);
            //如果新增节点的key小于parent的key,则当做左子节点
            if (cmp < 0)
                parent.left = e;
          //如果新增节点的key大于parent的key,则当做右子节点
            else
                parent.right = e;
            /*
             *  上面已经完成了排序二叉树的的构建,将新增节点插入该树中的合适位置
             *  下面fixAfterInsertion()方法就是对这棵树进行调整、平衡,具体过程参考上面的五种情况
             */
            fixAfterInsertion(e);
            //TreeMap元素数量 + 1
            size++;
            //TreeMap容器修改次数 + 1
            modCount++;
            return null;
        }

 //插入之后调整红黑树使其满足规则的操作函数fixAfterInsertion函数

/**
     * 新增节点后的修复操作
     * x 表示新增节点
     */
     private void fixAfterInsertion(Entry<K,V> x) {
            x.color = RED;    //新增节点的颜色为红色

            //循环 直到 x不是根节点,且x的父节点不为红色
            while (x != null && x != root && x.parent.color == RED) {
                //如果X的父节点(P)是其父节点的父节点(G)的左节点
                if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                    //获取X的叔节点(U)
                    Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                    //如果X的叔节点(U) 为红色(情况三)
                    if (colorOf(y) == RED) {     
                        //将X的父节点(P)设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将X的叔节点(U)设置为黑色
                        setColor(y, BLACK);
                        //将X的父节点的父节点(G)设置红色
                        setColor(parentOf(parentOf(x)), RED);
                        x = parentOf(parentOf(x));
                    }
                    //如果X的叔节点(U为黑色);这里会存在两种情况(情况四、情况五)
                    else {   
                        //如果X节点为其父节点(P)的右子树,则进行左旋转(情况四)
                        if (x == rightOf(parentOf(x))) {
                            //将X的父节点作为X
                            x = parentOf(x);
                            //右旋转
                            rotateLeft(x);
                        }
                        //(情况五)
                        //将X的父节点(P)设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将X的父节点的父节点(G)设置红色
                        setColor(parentOf(parentOf(x)), RED);
                        //以X的父节点的父节点(G)为中心右旋转
                        rotateRight(parentOf(parentOf(x)));
                    }
                }
                //如果X的父节点(P)是其父节点的父节点(G)的右节点
                else {
                    //获取X的叔节点(U)
                    Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                  //如果X的叔节点(U) 为红色(情况三)
                    if (colorOf(y) == RED) {
                        //将X的父节点(P)设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将X的叔节点(U)设置为黑色
                        setColor(y, BLACK);
                        //将X的父节点的父节点(G)设置红色
                        setColor(parentOf(parentOf(x)), RED);
                        x = parentOf(parentOf(x));
                    }
                  //如果X的叔节点(U为黑色);这里会存在两种情况(情况四、情况五)
                    else {
                        //如果X节点为其父节点(P)的右子树,则进行左旋转(情况四)
                        if (x == leftOf(parentOf(x))) {
                            //将X的父节点作为X
                            x = parentOf(x);
                           //右旋转
                            rotateRight(x);
                        }
                        //(情况五)
                        //将X的父节点(P)设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将X的父节点的父节点(G)设置红色
                        setColor(parentOf(parentOf(x)), RED);
                        //以X的父节点的父节点(G)为中心右旋转
                        rotateLeft(parentOf(parentOf(x)));
                    }
                }
            }
            //将根节点G强制设置为黑色
            root.color = BLACK;
        }

 

posted @ 2016-04-05 16:04  程序猿进化之路  阅读(246)  评论(0)    收藏  举报