Java集合系列之TreeMap源碼分析

來源:互聯網
上載者:User

標籤:java   collection   

一、概述

  TreeMap是基於紅/黑樹狀結構實現的。由於TreeMap實現了java.util.sortMap介面,集合中的映射關係是具有一定順序的,該映射根據其鍵的自然順序進行排序或者根據建立映射時提供的Comparator進行排序,具體取決於使用的構造方法。另外TreeMap中不允許鍵對象是null。

  1、什麼是紅/黑樹狀結構?

  紅/黑樹狀結構是一種特殊的二叉排序樹,主要有以下幾條基本性質:

  • 每個節點都只能是紅色或者黑色
  • 根節點是黑色
  • 每個葉子節點是黑色的
  • 如果一個節點是紅色的,則它的兩個子節點都是黑色的
  • 從任意一個節點到每個葉子節點的所有路徑都包含相同數目的黑色節點

  紅/黑樹狀結構的具體原理分析和演算法設計可參見博文:紅/黑樹狀結構的原理分析和演算法設計。

  2、key的兩種排序方式

  自然排序:TreeMap的所有key必須實現Comparable介面,並且所有key應該是同一個類的對象,否則將會拋ClassCastException異常

  指定排序:這種排序需要在構造TreeMap時,傳入一個Comparator對象,該對象負責對TreeMap中的key進行排序

  3、TreeMap類的繼承關係
public class TreeMap<K,V>   extends AbstractMap<K,V>    implements NavigableMap<K,V>, Cloneable, Serializable

  其中,NavigableMap介面是擴充的SortMap,具有了針對給定搜尋目標返回最接近匹配項的導航方法。其方法 lowerEntryfloorEntryceilingEntry 和 higherEntry 分別返回與小於、小於等於、大於等於、大於給定鍵的鍵關聯的 Map.Entry 對象,如果不存在這樣的鍵,則返回 null。類似地,方法 lowerKeyfloorKeyceilingKey 和 higherKey 只返回關聯的鍵。所有這些方法是為尋找條目而不是遍曆條目而設計的。 

二、TreeMap源碼分析  1、儲存結構

  TreeMap是基於紅/黑樹狀結構實現的,樹的節點定義如下:

 static final class Entry<K,V> implements Map.Entry<K,V>    {        //鍵        K key;        //值        V value;        //左孩子        Entry<K,V> left;        //右孩子        Entry<K,V> right;        //父節點        Entry<K,V> parent;        //節點顏色        boolean color = BLACK;        //建構函式        Entry(K key, V value, Entry<K,V> parent)        {            this.key = key;            this.value = value;            this.parent = parent;        }        ......}

  2、建構函式

  TreeMap有四種建構函式,分別對應不同的參數。

   //1.使用鍵的自然順序構造一個新的、空的樹映射    public TreeMap()     {        comparator = null;    }    //2.構造一個新的、空的樹映射,該映射根據給定比較子進行排序    public TreeMap(Comparator<? super K> comparator)    {        this.comparator = comparator;    }    /3.構造一個與給定映射具有相同映射關係的新的樹映射,該映射根據其鍵的自然順序 進行排序    public TreeMap(Map<? extends K, ? extends V> m)     {        comparator = null;        putAll(m);    }    //4.構造一個與指定有序映射具有相同映射關係和相同排序次序的新的樹映射    public TreeMap(SortedMap<K, ? extends V> m)    {        comparator = m.comparator();        try        {            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);        }        catch (java.io.IOException cannotHappen)        {        }        catch (ClassNotFoundException cannotHappen)        {        }    }

  3、TreeMap常用方法

  V put(K key,V value):將鍵值對(key,value)添加到TreeMap中

public V put(K key, V value)     {        Entry<K,V> t = root;        //若根節點為空白,則以(key,value)為參數建立節點        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        Comparator<? super K> cpr = comparator; //指定的排序演算法        if (cpr != null)         {            do {                parent = t;                cmp = cpr.compare(key, t.key);                if (cmp < 0)  //表示新增節點的key小於當前及節點的key,則以當前節點的左子節點作為新的當前節點                    t = t.left;                else if (cmp > 0) //表示新增節點的key大於當前及節點的key,則以當前節點的右子節點作為新的當前節點                    t = t.right;                else                    return t.setValue(value);  //相等則覆蓋舊值            } while (t != null);        }        //如果cpr為空白,則採用預設的排序演算法進行建立TreeMap集合        else        {            if (key == null)                throw new NullPointerException();            @SuppressWarnings("unchecked")                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);        if (cmp < 0)            parent.left = e;        else            parent.right = e;      //插入新的節點後,調用fixAfterInsertion調整紅/黑樹狀結構        fixAfterInsertion(e);        size++;        modCount++;        return null;    }

  Set<Map.Entry<K,V>> entrySet():返回此映射中包含的映射關係的Set視圖

 public Set<Map.Entry<K,V>> entrySet()     {        EntrySet es = entrySet;        return (es != null) ? es : (entrySet = new EntrySet());    }

  boolean remove(Object o): 如果此 TreeMap 中存在該鍵的映射關係,則將其刪除

 public boolean remove(Object o)     {                if (!(o instanceof Map.Entry))                    return false;                Map.Entry<K,V> entry = (Map.Entry<K,V>) o;                K key = entry.getKey();                if (!inRange(key))                    return false;                TreeMap.Entry<K,V> node = m.getEntry(key);                if (node!=null && valEquals(node.getValue(),                                            entry.getValue()))                {                    m.deleteEntry(node);                    return true;                }                return false;            }       }       

三、TreeMap應用範例程式碼
public class TreeMapDemo{    public static void main(String[] args)     {        //使用鍵的自然順序構造一個新的、空的樹映射        TreeMap<String,String> tm=new TreeMap<>();        tm.put("001", "中國");        tm.put("003", "美國");        tm.put("002", "法國");        System.out.println("調用entrySet得到索引值對集:");        Set<Entry<String, String>> result=tm.entrySet();        for(Entry<String, String> result2:result)        {            System.out.println(result2.getKey()+"---"+result2.getValue());        }        System.out.println("調用keySet得到鍵集:");        Set<String> result3=tm.keySet();        for(String str:result3)        {            System.out.println(str);        }        System.out.println("調用values得到值集:");        Collection result4=tm.values();        for(Object str:result4)            System.out.println(str);                    //建立一個帶比較子的TreeMap        TreeMap<String,String> tm2=new TreeMap<>(new ComparatorDemo());        tm2.put("001", "中國");        tm2.put("003", "美國");        tm2.put("002", "法國");        Set<Entry<String, String>> result5=tm2.entrySet();        for(Entry<String, String> result2:result5)        {            System.out.println(result2.getKey()+"---"+result2.getValue());        }    }}

  首先按照鍵的自然順序構建TreeMap,加入元素並遍曆:

  

  然後建立一個比較子類,實現Comparator介面

public class ComparatorDemo implements Comparator<String>{    public int compare(String o1, String o2) {        return 1;    }}

  在帶比較子的tm2中,按照與tm1相同的順序添加元素,此時再遍曆tm2,結果如下:

  

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Java集合系列之TreeMap源碼分析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.