集合包系列八 —— TreeMap

本系列文章所描述的所有類或接口都是基于 JDK 1.7的源碼,在其它 JDK 的實現(xiàn)方式中可能會有所不同弹囚。

一、實現(xiàn)方式

TreeMap 是一個支持排序的 Map 實現(xiàn)狼犯,其實現(xiàn)方式和 HashMap 并不相同。

二悯森、創(chuàng)建 TreeMap

在此步 TreeMap 只是將 comparator 屬性賦值為 null,如希望控制 TreeMap 中元素的存儲順序瓢姻,可使用帶 Comparator 參數(shù)的構(gòu)造器祝蝠。

    public TreeMap() {
        comparator = null;
    }

    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }

    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) {
        }
    }

三、添加元素 put(Object key, Object value)

當(dāng)調(diào)用 put 時,先要判斷 root 屬性是否為 null绎狭,如是,則創(chuàng)建一個新的 Entry 對象喇聊,并賦值給 root 屬性蹦狂。如不是,則首先判斷是否傳入了指定的 Comparator 實現(xiàn)凯楔,如已傳入,則基于紅黑樹的方式遍歷摆屯,基于 comparator 來比較 key 應(yīng)放在樹的左邊還是右邊,如找到相等的 key准验,則直接替換其 value富弦,并返回結(jié)束 put 操作沟娱,如沒有找到相等的 key腕柜,則一直尋找到左邊或右邊節(jié)點為 null 的元素,如 comparator 實現(xiàn)為 null砰蠢,則判斷 key 是否為 null唉铜,是則拋出 NullPointerException,否則將 key 轉(zhuǎn)化為 Comparable潭流,進(jìn)行與上面同樣的遍歷和比較過程。
  通過上面的步驟拆宛,如未找到相同的 key,則進(jìn)入以下過程讼撒,即創(chuàng)建一個新的 Entry 對象股耽,并將其 parent 設(shè)置為上面所尋找到的元素钳幅,并根據(jù)和 parent key 比較的情況來設(shè)置 parent 的 left 或 right 屬性。
  綜上所述敢艰,TreeMap 是一個典型的基于紅黑樹的實現(xiàn),因此它要求一定要有 key 比較的方法丽惭,要么傳入 Comparator 實現(xiàn)辈双,要么 key 對象實現(xiàn) Comparator 接口柜砾。

    public V put(K key, V value) {
        Entry<K,V> t = root;
        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)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            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);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

四、獲取元素 get(Object)

TreeMap 在查找 key 時就是個典型的紅黑樹查找過程证芭,從根對象開始往下比較担映,一直找到相等的 key,并返回其 value蝇完。
  和 put 時同樣的處理方式,如未傳入 Comparator 實現(xiàn)氢架,當(dāng)傳入的 Object 為 null 時朋魔,則直接拋出 NullPointerException。

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }

    final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
        Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }

五孙援、刪除元素 remove(Object)

remove 首先要做的是 getEntry扇雕,然后則是將此 Entry 從紅黑樹上刪除,并重新調(diào)整樹上的相關(guān)的節(jié)點洼裤。

    public V remove(Object key) {
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;

        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
    }

六溪王、判斷元素是否存在 containsKey(Object)

和 get 方法一樣值骇,都通過 getEntry 方法來完成,因此過程和 get 方法一樣道伟,只是 containsKey 直接判斷返回的 Entry 是否為 null使碾,為 null 則返回 false,不為 null 則返回 true票摇。

    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

七、遍歷元素 keySet()

調(diào)用 keySet 方法后返回 TreeMap 的內(nèi)部類 KeySet 對象的實例盆色,iterator 的遍歷從根開始祟剔,基于紅黑樹順序完成。

    public Set<K> keySet() {
        return navigableKeySet();
    }

八物延、注意要點

對 TreeMap 而言,最應(yīng)了解的有以下幾點:

  • TreeMap 基于紅黑樹實現(xiàn)浑吟,無容量限制案训;
  • TreeMap 是非線程安全的。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末忿项,一起剝皮案震驚了整個濱河市城舞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌家夺,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榨为,死亡現(xiàn)場離奇詭異,居然都是意外死亡随闺,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門龄句,熙熙樓的掌柜王于貴愁眉苦臉地迎上來散罕,“玉大人,你說我怎么就攤上這事职抡×蛞” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長岳遥。 經(jīng)常有香客問我,道長派继,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任驾窟,我火速辦了婚禮认轨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恩急。我一直安慰自己纪蜒,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布随珠。 她就那樣靜靜地躺著灭袁,像睡著了一般窗看。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上举娩,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天构罗,我揣著相機(jī)與錄音,去河邊找鬼芙代。 笑死,一個胖子當(dāng)著我的面吹牛纹烹,可吹牛的內(nèi)容都是我干的召边。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼片挂,長吁一口氣:“原來是場噩夢啊……” “哼贞盯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闷愤,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤件余,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蛾扇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡坟漱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年更哄,在試婚紗的時候發(fā)現(xiàn)自己被綠了腥寇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片觅捆。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡栅炒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赢赊,到底是詐尸還是另有隱情,我是刑警寧澤释移,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布玩讳,位于F島的核電站涩蜘,受9級特大地震影響熏纯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剩辟,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一往扔、第九天 我趴在偏房一處隱蔽的房頂上張望熊户。 院中可真熱鬧,春花似錦嚷堡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至友鼻,卻和暖如春闺骚,著一層夾襖步出監(jiān)牢的瞬間妆档,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工胸梆, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留须板,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓洋措,卻偏偏與公主長得像杰刽,于是被迫代替她去往敵國和親菠发。 傳聞我的和親對象是個殘疾皇子贺嫂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一曲饱、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對于byte類型而言...
    龍貓小爺閱讀 4,259評論 0 16
  • java筆記第一天 == 和 equals ==比較的比較的是兩個變量的值是否相等扩淀,對于引用型變量表示的是兩個變量...
    jmychou閱讀 1,497評論 0 3
  • Collection接口 Collection接口是所有集合的祖先類。他有兩個構(gòu)造方法驻谆,一個無參構(gòu)造,一個是帶Co...
    夜幕繁華閱讀 593評論 0 0
  • 4 TreeMap 上一篇勺卢,介紹了集合框架中的HashMap對象象对,主要講述了HashMap的底層實現(xiàn)和基本操作。本...
    賈博巖閱讀 121,450評論 15 98
  • title: java集合框架學(xué)習(xí)總結(jié) tags:集合框架 categories:總結(jié) date: 2017-03...
    行徑行閱讀 1,685評論 0 2