【java集合】Map--TreeMap

一、关于红黑二叉树简介
TreeMap 是红黑二叉树算法实现。
- 红黑树简介
红黑树又称红-黑二叉树,它首先是一颗二叉树,它具有二叉树所有的特性。同时红黑树更是一颗自平衡的排序二叉树。
基本的二叉树需要满足一个基本性质–即树中的任何节点的值大于它的左子节点,且小于它的右子节点。按照这个基本性质使得树的检索效率大大提高。
我们知道在生成二叉树的过程是非常容易失衡的,最坏的情况就是一边倒(只有右/左子树),这样势必会导致二叉树的检索效率大大降低(O(n)),所以为了维持二叉树的平衡,大牛们提出了各种实现的算法,如:AVL,SBT,伸展树,TREAP ,红黑树等等。
平衡二叉树必须具备如下特性:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。也就是说该二叉树的任何一个等等子节点,其左右子树的高度都相近。
这里写图片描述
红黑树顾名思义就是红色或者黑色平衡二叉树,通过颜色约束二叉树的平衡。
对于一颗有效且平衡的二叉树需要遵守如下规则:

  • 每个节点只能是红色或者黑色
  • 根节点是黑色
  • 每个叶节点(NIL 节点,空节点)是黑色
  • 一个节点是红色,则它的两个节点都是黑色,不能包含两个相邻的红色节点
  • 从任何一个节点到叶子节点,黑色节点的个数是相同的

详细了解红黑树结构,请参考:

1、红黑树数据结构剖析:http://www.cnblogs.com/fanzhidongyzby/p/3187912.html
2、红黑二叉树详解及理论分析 :http://blog.csdn.NET/kartorz/article/details/8865997
3、教你透彻了解红黑树 :blog.csdn.Net/v_july_v/article/details/6105630
4、经典算法研究系列:五、红黑树算法的实现与剖析 :http://blog.csdn.net/v_JULY_v/article/details/6109153
5、示例,红黑树插入和删除过程:http://saturnman.blog.163.com/blog/static/557611201097221570/
6、红黑二叉树详解及理论分析 :http://blog.csdn.net/kartorz/article/details/8865997

二、TreeMap重要方法源码解析

put 方法:

    public V put(K key, V value) {
        Entry<K,V> t = root;
        //<1>获取根节点,如果根节点为null,作为根节点插入
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        //<2>获取排序仪
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
        //<2.1> 排序仪器不为空,do-while循环遍历寻找节点最底层叶子节点
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                //根据“即树中的任何节点的值大于它的左子节点,且小于它的右子节点”特性,生成如下逻辑,
                //如果 源节点key小于目标节点key,从"左"节点遍历,否则从"右"节点遍历。
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
        //<2.2> 排序仪器为空,按自然排序
            if (key == null)
                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);
        }
        //<3>遍历到最底层节点位置,作为新节点的父节点
        Entry<K,V> e = new Entry<>(key, value, parent);
        //<3.1>还是遵守“即树中的任何节点的值大于它的左子节点,且小于它的右子节点”特性
        //新key小于父节点key,作为左节点插入;大于,则作为右节点插入
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

删除节点

  /**
     * Delete node p, and then rebalance the tree.
     */
    private void deleteEntry(Entry<K,V> p) {
        modCount++;
        size--;

        //<1>当前节点有左节点和右节点
        if (p.left != null && p.right != null) {
        //<1.1>寻找替换节点,注:删除不是直接删除节点,而是找替换节点替换当前节点
            Entry<K,V> s = successor(p);
            p.key = s.key;
            p.value = s.value;
            p = s;
        } // p has 2 children

        // Start fixup at replacement node, if it exists.
        //<2> 如果<1>找到的替换节点包含左节点,则用左节点替换,否则用右节点替换
        Entry<K,V> replacement = (p.left != null ? p.left : p.right);
        //<2.1> 替换节点不为空
        if (replacement != null) {
            // Link replacement to parent
            replacement.parent = p.parent;
            //<2.1.1>当前要删除节点为根节点,直接将替换节点设置为根节点
            if (p.parent == null)
                root = replacement;
            //<2.1.2>当前要删除节点为左节点,替换节点替换左节点
            else if (p == p.parent.left)
                p.parent.left  = replacement;
            //<2.1.3>当前要删除节点为右节点,替换节点替换右节点
            else
                p.parent.right = replacement;

            //<2.2> 删除P节点
            p.left = p.right = p.parent = null;

            //<2.3> 如果当前节点颜色为黑色,调整红黑树使其保持平衡
            //注:遵守红黑树特性:任意节点下的子节点的黑色节点树相同
            if (p.color == BLACK)
                fixAfterDeletion(replacement);
        } else if (p.parent == null) { // <2.2>当前要删除节点为父节点.
            root = null;
        } else { //<2.3>当前要删除节点没有子节点,直接删除该节点
            if (p.color == BLACK)
                fixAfterDeletion(p);

            if (p.parent != null) {
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            }
        }
    }

/**
* 选择替换节点
*/
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {  
        if (t == null)  
            return null;  
        /* 
         * 寻找右子树的最左子树 
         */  
        else if (t.right != null) {  
            Entry<K,V> p = t.right;  
            while (p.left != null)  
                p = p.left;  
            return p;  
        }   
        /* 
         * 选择左子树的最右子树 
         */  
        else {  
            Entry<K,V> p = t.parent;  
            Entry<K,V> ch = t;  
            while (p != null && ch == p.right) {  
                ch = p;  
                p = p.parent;  
            }  
            return p;  
        }  
    }  

/**
* 替换节点后,调整红黑二叉树,使其保持平衡
*/
private void fixAfterDeletion(Entry<K,V> x) {  
        // 删除节点需要一直迭代,知道 直到 x 不是根节点,且 x 的颜色是黑色  
        while (x != root && colorOf(x) == BLACK) {  
            if (x == leftOf(parentOf(x))) {      //若X节点为左节点  
                //获取其兄弟节点  
                Entry<K,V> sib = rightOf(parentOf(x));  

                /* 
                 * 如果兄弟节点为红色----(情况3.1) 
                 * 策略:改变W、P的颜色,然后进行一次左旋转 
                 */  
                if (colorOf(sib) == RED) {       
                    setColor(sib, BLACK);       
                    setColor(parentOf(x), RED);    
                    rotateLeft(parentOf(x));  
                    sib = rightOf(parentOf(x));  
                }  

                /* 
                 * 若兄弟节点的两个子节点都为黑色----(情况3.2) 
                 * 策略:将兄弟节点编程红色 
                 */  
                if (colorOf(leftOf(sib))  == BLACK &&  
                    colorOf(rightOf(sib)) == BLACK) {  
                    setColor(sib, RED);  
                    x = parentOf(x);  
                }   
                else {  
                    /* 
                     * 如果兄弟节点只有右子树为黑色----(情况3.3) 
                     * 策略:将兄弟节点与其左子树进行颜色互换然后进行右转 
                     * 这时情况会转变为3.4 
                     */  
                    if (colorOf(rightOf(sib)) == BLACK) {  
                        setColor(leftOf(sib), BLACK);  
                        setColor(sib, RED);  
                        rotateRight(sib);  
                        sib = rightOf(parentOf(x));  
                    }  
                    /* 
                     *----情况3.4 
                     *策略:交换兄弟节点和父节点的颜色, 
                     *同时将兄弟节点右子树设置为黑色,最后左旋转 
                     */  
                    setColor(sib, colorOf(parentOf(x)));  
                    setColor(parentOf(x), BLACK);  
                    setColor(rightOf(sib), BLACK);  
                    rotateLeft(parentOf(x));  
                    x = root;  
                }  
            }   

            /** 
             * X节点为右节点与其为做节点处理过程差不多,这里就不在累述了 
             */  
            else {  
                Entry<K,V> sib = leftOf(parentOf(x));  

                if (colorOf(sib) == RED) {  
                    setColor(sib, BLACK);  
                    setColor(parentOf(x), RED);  
                    rotateRight(parentOf(x));  
                    sib = leftOf(parentOf(x));  
                }  

                if (colorOf(rightOf(sib)) == BLACK &&  
                    colorOf(leftOf(sib)) == BLACK) {  
                    setColor(sib, RED);  
                    x = parentOf(x);  
                } else {  
                    if (colorOf(leftOf(sib)) == BLACK) {  
                        setColor(rightOf(sib), BLACK);  
                        setColor(sib, RED);  
                        rotateLeft(sib);  
                        sib = leftOf(parentOf(x));  
                    }  
                    setColor(sib, colorOf(parentOf(x)));  
                    setColor(parentOf(x), BLACK);  
                    setColor(leftOf(sib), BLACK);  
                    rotateRight(parentOf(x));  
                    x = root;  
                }  
            }  
        }  

        setColor(x, BLACK);  
    } 

原文链接:http://blog.csdn.net/chenssy/article/details/26668941

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值