extends AbstractMap K , V > implements NavigableMap K , V >, Cloneable , java.io.Serializable TreeMap 首先繼承了 AbstractMap 抽象類,表示它具有散列表的性質(zhì),也就是由 key-value 組成。 其次 TreeMap 實(shí)現(xiàn)了 NavigableMap 接口,該" />
0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

JDK中java.util.TreeMap 類的介紹

科技綠洲 ? 來(lái)源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-10 11:45 ? 次閱讀

本篇文章給大家介紹基于樹(shù)實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)——TreeMap

1、TreeMap 定義

聽(tīng)名字就知道,TreeMap 是由Tree 和 Map 集合有關(guān)的,沒(méi)錯(cuò),TreeMap 是由紅黑樹(shù)實(shí)現(xiàn)的有序的 key-value 集合。

PS:想要學(xué)懂TreeMap的實(shí)現(xiàn)原理,紅黑樹(shù)的了解是必不可少的?。。?/p>

public class TreeMap< K,V >
    extends AbstractMap< K,V >
    implements NavigableMap< K,V >, Cloneable, java.io.Serializable

圖片

TreeMap 首先繼承了 AbstractMap 抽象類,表示它具有散列表的性質(zhì),也就是由 key-value 組成。

其次 TreeMap 實(shí)現(xiàn)了 NavigableMap 接口,該接口支持一系列獲取指定集合的導(dǎo)航方法,比如獲取小于指定key的集合。

最后分別實(shí)現(xiàn) Serializable 接口以及 Cloneable 接口,分別表示支持對(duì)象序列化以及對(duì)象克隆。

2、字段定義

①、Comparator

/**
     * The comparator used to maintain order in this tree map, or
     * null if it uses the natural ordering of its keys.
     *
     * @serial
     */
    private final Comparator< ? super K > comparator;

可以看上面的英文注釋,Comparator 是用來(lái)維護(hù)treemap集合中的順序,如果為null,則按照key的自然順序。

Comparator 是一個(gè)接口,排序時(shí)需要實(shí)現(xiàn)其 compare 方法,該方法返回正數(shù),零,負(fù)數(shù)分別代表大于,等于,小于。那么怎么使用呢?這里舉個(gè)例子:

這里有一個(gè)Person類,里面有兩個(gè)屬性pname,page,我們將該person對(duì)象放入ArrayList集合時(shí),需要對(duì)其按照年齡進(jìn)行排序。

package com.ys.test;

/**
 * Create by YSOcean
 */
public class Person {
    private String pname;
    private Integer page;

    public Person() {
    }

    public Person(String pname, Integer page) {
        this.pname = pname;
        this.page = page;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public Integer getPage() {
        return page;
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    @Override
    public String toString() {
        return "Person{" +
                "pname='" + pname + ''' +
                ", page=" + page +
                '}';
    }
}

打印結(jié)果為:

圖片

②、Entry

private transient Entry< K,V > root;

對(duì)于Entry詳細(xì)源碼這里不列舉了,主要看幾個(gè)字段:

K key;
V value;
Entry K,V > left;
Entry K,V > right;
Entry K,V > parent;
boolean color = BLACK;

相信對(duì)紅黑樹(shù)這種數(shù)據(jù)結(jié)構(gòu)了解的人,一看這幾個(gè)字段就明白了,這也印證了前面所說(shuō)的TreeMap底層有紅黑樹(shù)這種數(shù)據(jù)結(jié)構(gòu)。

③、size

/**
     * The number of entries in the tree
     */
    private transient int size = 0;

用來(lái)表示entry的個(gè)數(shù),也就是key-value的個(gè)數(shù)。

④、modCount

/**
     * The number of structural modifications to the tree.
     */
    private transient int modCount = 0;

基本上前面講的在ArrayList,LinkedList,HashMap等線程不安全的集合都有此字段,用來(lái)實(shí)現(xiàn)Fail-Fast 機(jī)制,如果在迭代這些集合的過(guò)程中,有其他線程修改了這些集合,就會(huì)拋出ConcurrentModificationException異常。

⑤、紅黑樹(shù)常量

private static final boolean RED   = false;
    private static final boolean BLACK = true;

3、構(gòu)造函數(shù)

①、無(wú)參構(gòu)造函數(shù)

1     public TreeMap() {
2         comparator = null;
3     }

比較器 comparator 置為 null,表示按照key的自然順序進(jìn)行排序。

②、帶比較器的構(gòu)造函數(shù)

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

需要自己實(shí)現(xiàn)Comparator。

③、構(gòu)造包含指定map集合的元素

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

使用該構(gòu)造器創(chuàng)建的TreeMap,會(huì)默認(rèn)插入m表示的集合元素,并且comparator表示按照自然順序進(jìn)行插入。

④、帶 SortedMap的構(gòu)造函數(shù)

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

和上面帶Map的構(gòu)造函數(shù)不一樣,map是無(wú)序的,而SortedMap 是有序的,使用 buildFromSorted() 方法將SortedMap集合中的元素插入到TreeMap 中。

4、添加元素

//添加元素
    public V put(K key, V value) {
        TreeMap.Entry< K,V > t = root;
        //如果根節(jié)點(diǎn)為空,即TreeMap中一個(gè)元素都沒(méi)有,那么設(shè)置新添加的元素為根節(jié)點(diǎn)
        //并且設(shè)置集合大小size=1,以及modCount+1,這是用于快速失敗
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new TreeMap.Entry<  >(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        TreeMap.Entry< K,V > parent;
        // split comparator and comparable paths
        Comparator< ? super K > cpr = comparator;
        //如果比較器不為空,即初始化TreeMap構(gòu)造函數(shù)時(shí),有傳遞comparator類
        //那么插入新的元素時(shí),按照comparator實(shí)現(xiàn)的類進(jìn)行排序
        if (cpr != null) {
            //通過(guò)do-while循環(huán)不斷遍歷樹(shù),調(diào)用比較器對(duì)key值進(jìn)行比較
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    //遇到key相等,直接將新值覆蓋到原值上
                    return t.setValue(value);
            } while (t != null);
        }
        //如果比較器為空,即初始化TreeMap構(gòu)造函數(shù)時(shí),沒(méi)有傳遞comparator類
        //那么插入新的元素時(shí),按照key的自然順序
        else {
            //如果key==null,直接拋出異常
            //注意,上面構(gòu)造TreeMap傳入了Comparator,是可以允許key==null
            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);
        }
        //找到父親節(jié)點(diǎn),根據(jù)父親節(jié)點(diǎn)創(chuàng)建一個(gè)新節(jié)點(diǎn)
        TreeMap.Entry< K,V > e = new TreeMap.Entry<  >(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        //修正紅黑樹(shù)(包括節(jié)點(diǎn)的左旋和右旋,具體可以看我Java數(shù)據(jù)結(jié)構(gòu)和算法中對(duì)紅黑樹(shù)的介紹)
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

添加元素,如果初始化TreeMap構(gòu)造函數(shù)時(shí),沒(méi)有傳遞comparator類,是不允許插入key==null的鍵值對(duì)的,相反,如果實(shí)現(xiàn)了Comparator,則可以傳遞key=null的鍵值對(duì)。

另外,當(dāng)插入一個(gè)新的元素后(除了根節(jié)點(diǎn)),會(huì)對(duì)TreeMap數(shù)據(jù)結(jié)構(gòu)進(jìn)行修正,也就是對(duì)紅黑樹(shù)進(jìn)行修正,使其滿足紅黑樹(shù)的幾個(gè)特點(diǎn),具體修正方法包括改變節(jié)點(diǎn)顏色,左旋,右旋等操作,這里我不做詳細(xì)介紹了.

5、刪除元素

①、根據(jù)key刪除

public V remove(Object key) {
        //根據(jù)key找到該節(jié)點(diǎn)
        TreeMap.Entry< K,V > p = getEntry(key);
        if (p == null)
            return null;
        //獲取該節(jié)點(diǎn)的value,并返回
        V oldValue = p.value;
        //調(diào)用deleteEntry()方法刪除節(jié)點(diǎn)
        deleteEntry(p);
        return oldValue;
    }

    private void deleteEntry(TreeMap.Entry< K,V > p) {
        modCount++;
        size--;

        //如果刪除節(jié)點(diǎn)的左右節(jié)點(diǎn)都不為空,即有兩個(gè)孩子
        if (p.left != null && p.right != null) {
            //得到該節(jié)點(diǎn)的中序后繼節(jié)點(diǎn)
            TreeMap.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.
        TreeMap.Entry< K,V > replacement = (p.left != null ? p.left : p.right);
        //待刪除節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn),直接刪除該節(jié)點(diǎn),并用該節(jié)點(diǎn)的唯一子節(jié)點(diǎn)頂替該節(jié)點(diǎn)
        if (replacement != null) {
            // Link replacement to parent
            replacement.parent = p.parent;
            if (p.parent == null)
                root = replacement;
            else if (p == p.parent.left)
                p.parent.left  = replacement;
            else
                p.parent.right = replacement;

            // Null out links so they are OK to use by fixAfterDeletion.
            p.left = p.right = p.parent = null;

            // Fix replacement
            if (p.color == BLACK)
                fixAfterDeletion(replacement);

            //TreeMap中只有待刪除節(jié)點(diǎn)P,也就是只有一個(gè)節(jié)點(diǎn),直接返回nul即可
        } else if (p.parent == null) { // return if we are the only node.
            root = null;
        } else { //  No children. Use self as phantom replacement and unlink.
            //待刪除節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn),即為葉子節(jié)點(diǎn),直接刪除即可
            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;
            }
        }
    }

刪除節(jié)點(diǎn)分為四種情況:

1、根據(jù)key沒(méi)有找到該節(jié)點(diǎn):也就是集合中不存在這一個(gè)節(jié)點(diǎn),直接返回null即可。

2、根據(jù)key找到節(jié)點(diǎn),又分為三種情況:

①、待刪除節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn),即為葉子節(jié)點(diǎn):直接刪除該節(jié)點(diǎn)即可。

②、待刪除節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn):那么首先找到待刪除節(jié)點(diǎn)的子節(jié)點(diǎn),然后刪除該節(jié)點(diǎn),用其唯一子節(jié)點(diǎn)頂替該節(jié)點(diǎn)。

③、待刪除節(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn):首先找到該節(jié)點(diǎn)的中序后繼節(jié)點(diǎn),然后把這個(gè)后繼節(jié)點(diǎn)的內(nèi)容復(fù)制給待刪除節(jié)點(diǎn),然后刪除該中序后繼節(jié)點(diǎn),刪除過(guò)程又轉(zhuǎn)換成前面①、②兩種情況了,這里主要是找到中序后繼節(jié)點(diǎn),相當(dāng)于待刪除節(jié)點(diǎn)的一個(gè)替身。

6、查找元素

①、根據(jù)key查找

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

    final TreeMap.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();
        @SuppressWarnings("unchecked")
        Comparable< ? super K > k = (Comparable< ? super K >) key;
        TreeMap.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;
    }

7、遍歷元素

通常有下面兩種方法,第二種方法效率要快很多。

TreeMap< String,Integer > map = new TreeMap<  >();
map.put("A",1);
map.put("B",2);
map.put("C",3);

//第一種方法
//首先利用keySet()方法得到key的集合,然后利用map.get()方法根據(jù)key得到value
Iterator< String > iterator = map.keySet().iterator();
while(iterator.hasNext()){
    String key = iterator.next();
    System.out.println(key+":"+map.get(key));
}

//第二種方法
Iterator< Map.Entry< String,Integer >> iterator1 = map.entrySet().iterator();
while(iterator1.hasNext()){
    Map.Entry< String,Integer > entry = iterator1.next();
    System.out.println(entry.getKey()+":"+entry.getValue());
}

8、小結(jié)

好了,這就是JDK中java.util.TreeMap 類的介紹。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2943

    瀏覽量

    104106
  • MAP
    MAP
    +關(guān)注

    關(guān)注

    0

    文章

    48

    瀏覽量

    15106
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    568

    瀏覽量

    40030
  • JDK
    JDK
    +關(guān)注

    關(guān)注

    0

    文章

    80

    瀏覽量

    16550
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    java jdk安裝參考步驟

    1、把jdk-8u5-linux-x64.gz解壓,然后把解壓的文件夾放到/usr/lib/jvm/下,并重命名為jdk,這個(gè)目錄可以自定義。2、編輯~/.basrc文件,在文件的末尾追加下面的命令
    發(fā)表于 09-25 16:43

    樹(shù)莓派如何安裝Java JDK?

    。Oracle Java 具有其他一些商業(yè)功能,并且許可僅允許非商業(yè)用途。下面介紹如何在樹(shù)莓派的 Raspbian OS 上安裝Java(OpenJDK)?! ∵\(yùn)行以下命令安裝最新的 JDK
    發(fā)表于 02-02 16:37

    HarmonyOS方舟開(kāi)發(fā)框架容器API的介紹與使用

    對(duì)外提供。通過(guò)對(duì)存儲(chǔ)位置以及屬性的限制,讓每種類型的數(shù)據(jù)都能在完成自身功能的基礎(chǔ)上剪除冗余分支,保證了數(shù)據(jù)的高效訪問(wèn),提升了應(yīng)用的性能。 本期,我們將為大家介紹方舟開(kāi)發(fā)框架容器的各種類型以及相關(guān)
    發(fā)表于 03-07 11:40

    看看基于JDK自帶JVM工具的用法

    用到命令,下面圍繞一個(gè)微服務(wù)的啟動(dòng)和運(yùn)行,來(lái)看看基于JDK自帶JVM工具的用法;三、命令行工具1、jps命令jps :虛擬機(jī)進(jìn)程狀態(tài)工具,該命令在Java環(huán)境部署和服務(wù)啟動(dòng)查看時(shí)經(jīng)常用到,首先在本地
    發(fā)表于 11-16 15:30

    java jdk6.0官方下載

    java jdk6.0下載如何件: java jdk6.0安裝步驟: 第一步 JDK1.6的安裝步驟 第一步雙擊安裝文件
    發(fā)表于 10-17 11:47 ?155次下載
    <b class='flag-5'>java</b> <b class='flag-5'>jdk</b>6.0官方下載

    java基礎(chǔ)——java.util.ConcurrentModificationException

    本文檔內(nèi)容介紹java基礎(chǔ)java.util.ConcurrentModificationException,供參考
    發(fā)表于 03-13 11:31 ?2次下載

    JavaArrays是什么 Arrays常用方法

    了解Arrays的概念 **A****rrays** 位于java.util包下,Arrays是一個(gè)操作數(shù)組的工具。 Arrays常用方法 Arrays.fill:
    的頭像 發(fā)表于 02-17 15:11 ?930次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>中</b>Arrays<b class='flag-5'>類</b>是什么 Arrays常用方法

    JDKjava.util.HashSet 介紹

    JDK1.8 ,HashMap 是由 數(shù)組+鏈表+紅黑樹(shù)構(gòu)成,相對(duì)于早期版本的 JDK HashMap 實(shí)現(xiàn),新增了紅黑樹(shù)作為底層數(shù)據(jù)結(jié)構(gòu),在數(shù)據(jù)量較大且哈希碰撞較多時(shí),能夠極大的增加檢索
    的頭像 發(fā)表于 10-09 10:50 ?474次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java.util</b>.HashSet <b class='flag-5'>類</b>的<b class='flag-5'>介紹</b>

    Java時(shí)間轉(zhuǎn)換方案

    LocalDate 的過(guò)程,我們使用 Date Java 8 新增的 toInstant() 方法進(jìn)行轉(zhuǎn)換。 當(dāng)我們轉(zhuǎn)換一個(gè) Instant 對(duì)象時(shí),需要使用 ZoneId
    的頭像 發(fā)表于 10-09 15:48 ?403次閱讀

    JDKjava.util.ArrayList 介紹

    AbstractList E > implements List E >, RandomAccess , Cloneable , java.io.Serializable ①、實(shí)現(xiàn) RandomAccess 接口 這是
    的頭像 發(fā)表于 10-10 15:51 ?563次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java.util</b>.ArrayList <b class='flag-5'>類</b>的<b class='flag-5'>介紹</b>

    JDKjava.lang.Arrays 的源碼解析

    日常開(kāi)發(fā),我們會(huì)使用各種工具,利用封裝好的輪子,能讓我們的開(kāi)發(fā)事半功倍。但是在JDK,有一個(gè)特別的工具——
    的頭像 發(fā)表于 10-11 15:31 ?498次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java</b>.lang.Arrays <b class='flag-5'>類</b>的源碼解析

    JDKjava.lang.String 的源碼解析

    1、String 的定義 public final class String implements java.io.Serializable, Comparable, CharSequence
    的頭像 發(fā)表于 10-13 10:51 ?384次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java</b>.lang.String <b class='flag-5'>類</b>的源碼解析

    javautil包下有哪些

    Javautil包下,包含了許多,用于提供各種常見(jiàn)的實(shí)用工具和數(shù)據(jù)結(jié)構(gòu)。以下是一些常見(jiàn)的: ArrayList:動(dòng)態(tài)數(shù)組,可以根據(jù)需要自動(dòng)調(diào)整大小。 LinkedList:雙向
    的頭像 發(fā)表于 11-22 15:04 ?974次閱讀

    weblogic修改jdk路徑

    )路徑的情況。本文將詳細(xì)介紹如何在WebLogic修改JDK路徑。 一、背景介紹 Java Development Kit(
    的頭像 發(fā)表于 12-05 14:46 ?1060次閱讀

    OpenHarmony語(yǔ)言基礎(chǔ)庫(kù)【@ohos.util.TreeMap (非線性容器TreeMap)】

    TreeMap可用于存儲(chǔ)具有關(guān)聯(lián)關(guān)系的key-value鍵值對(duì)集合,存儲(chǔ)元素key值唯一,每個(gè)key對(duì)應(yīng)一個(gè)value。
    的頭像 發(fā)表于 04-28 15:23 ?212次閱讀
    OpenHarmony語(yǔ)言基礎(chǔ)<b class='flag-5'>類</b>庫(kù)【@ohos.<b class='flag-5'>util.TreeMap</b> (非線性容器<b class='flag-5'>TreeMap</b>)】