day26--Java集合09

来源:https://www.cnblogs.com/liyuelian/archive/2022/08/25/16625440.html
-Advertisement-
Play Games

Java集合09 18.TreeSet 元素無序:插入順序和輸出順序不一致 可以按照一定的規則進行排序,具體排序方式取決於構造方法: TreeSet () :根據其元素的自然排序進行排序 TreeSet (Comparator comparator) :根據指定的比較器進行排序 沒有帶索引的方法,所 ...


Java集合09

18.TreeSet

  • 元素無序:插入順序和輸出順序不一致
  • 可以按照一定的規則進行排序,具體排序方式取決於構造方法:
    • TreeSet () :根據其元素的自然排序進行排序
    • TreeSet (Comparator comparator) :根據指定的比較器進行排序
  • 沒有帶索引的方法,所以不能使用普通for迴圈遍歷
  • 由於是Set集合,不包含重覆元素

[TreeSet集合的理解(自然排序和比較器排序)-CSDN博客]

例子:

package li.collection.set.treeset;

import java.util.Comparator;
import java.util.TreeSet;

@SuppressWarnings("all")
public class TreeSet_ {
    public static void main(String[] args) {

        //TreeSet treeSet = new TreeSet();
        TreeSet treeSet = new TreeSet(new Comparator() {//匿名內部類
            @Override
            public int compare(Object o1, Object o2) {
                //下麵調用String的compareTo方法進行字元串的小的比較
                return ((String)o2).compareTo((String)o1);//從大到小
            }
        });
        //添加數據
        treeSet.add("lucy");
        treeSet.add("bob");
        treeSet.add("smith");
        treeSet.add("join");
        treeSet.add("mary");
        treeSet.add("q");
        System.out.println(treeSet);//[smith, q, mary, lucy, join, bob]

    }
}
  1. 當我們使用無參構造器 創建TreeSet時,會有一個預設的比較器

    TreeSet可以對集合中的元素進行排序,在添加元素的時候會自動去調用Comparable介面的compareTo方法

    有些泛型類已經寫好了排序規則,比如String 和 Integer 都已經實現了Comparable介面,也重寫了compareTo方法

  2. 現在希望添加的元素按照字元串大小來排序

  3. 使用TreeSet提供的一個構造器,可以傳入一個比較器(匿名內部類),並指定排序規則

    TreeSet treeSet = new TreeSet(new Comparator() {//匿名內部類
                @Override
                public int compare(Object o1, Object o2) {
                    //下麵調用String的compareTo方法進行字元串的小的比較
                    return ((String)o2).compareTo((String)o1);//從大到小
                }
            });
    
  4. 簡單看看源碼
    4.1 構造器把傳入的比較器對象付賦給了TreeSet底層TreeMap的屬性this.comparator

    image-20220825161645515
    image-20220825161555778

    4.2在調用treeSet.add("lucy")時,在底層會執行到:

    if (cpr != null) {//cpr就是我們的匿名內部類(對象)
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);//動態綁定到我們的匿名內部類(對象)的compareTo方法
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else//如果相等,即返回0,這個key就沒有加入
                return t.setValue(value);
        } while (t != null);
    }
    

思考:如果要求加入的元素按照長度大小排序該怎麼寫?

package li.collection.set.treeset;

import java.util.Comparator;
import java.util.TreeSet;

@SuppressWarnings("all")
public class TreeSet_ {
    public static void main(String[] args) {

        TreeSet treeSet = new TreeSet(new Comparator() {//匿名內部類
            @Override
            public int compare(Object o1, Object o2) {
                //按照長度大小排序
                return ((String)o2).length()-((String)o1).length();//長度從大到小
            }
        });

        treeSet.add("lucy");
        treeSet.add("bob");
        treeSet.add("q");
        System.out.println(treeSet);//[lucy, bob, q]

    }
}

問:如果此時再使用add()方法添加一個"jack"字元串,這個字元串可以添加進treeSet嗎?

image-20220825164908470

如上圖,答案是不能。之前已經說過,在使用add()方法時,底層會調用:

if (cpr != null) {//cpr就是我們的匿名內部類(對象)
    do {
        parent = t;
        cmp = cpr.compare(key, t.key);//動態綁定到我們的匿名內部類(對象)的compareTo方法
        if (cmp < 0)
            t = t.left;
        else if (cmp > 0)
            t = t.right;
        else//如果相等,即返回0,這個key就沒有加入
            return t.setValue(value);
    } while (t != null);
}

由於我們重寫了compareTo方法,方法此時返回的是兩個元素長度之差。

在do...while迴圈比較時,因為在加入“jack”之前已經有一個相同長度為4的字元串“lucy”,所以compareTo返回的值為0,即cmp=0,執行語句return t.setValue(value);

即 認為是同一個key,因此“jack”無法加入集合treeSet

19.TreeMap

image-20220817180129001

例子:

package li.map.treemap;
import java.util.Comparator;
import java.util.TreeMap;

@SuppressWarnings("all")
public class TreeMap_ {
    public static void main(String[] args) {
        //使用預設的構造器穿件TreeMap,是無序的(也沒有排序)
        //要求:按照傳入的字元串(key)的大小進行排序
        //TreeMap treeMap = new TreeMap();
        TreeMap treeMap = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //按照傳入的字元串(key)的大小進行排序
                //return ((String)o2).compareTo((String)o1);

                //按照key的字元串長度大小排序
                return ((String)o2).length()-((String)o1).length();
            }
        });
        treeMap.put("jack","傑克");
        treeMap.put("tom","湯姆");
        treeMap.put("kristina","克裡斯提諾");
        treeMap.put("smith","史密斯");
        
        System.out.println(treeMap);//按照key的長度排序
        // {kristina=克裡斯提諾, smith=史密斯, jack=傑克, tom=湯姆}
    }
}

如下圖:打上斷點,點擊debug,點擊force step into進入到構造器中

image-20220825175954213
  1. 把傳入的實現了Comparator介面的匿名內部類(對象),傳給 了TreeMap的comparator屬性
image-20220825180139851
  1. 接下來調用put方法:

    public V put(K key, V value) 
    { 
        // 先以 t 保存鏈表的 root 節點
        Entry<K,V> t = root; 
        // 如果 t==null,表明是一個空鏈表,即該 TreeMap 里沒有任何 Entry 
        if (t == null) 
        { 
            // 將新的 key-value 創建一個 Entry,並將該 Entry 作為 root 
            root = new Entry<K,V>(key, value, null); 
            // 設置該 Map 集合的 size 為 1,代表包含一個 Entry 
            size = 1; 
            // 記錄修改次數為 1 
            modCount++; 
            return null; 
        } 
        int cmp; 
        Entry<K,V> parent; 
        Comparator<? super K> cpr = comparator; 
        // 如果比較器 cpr 不為 null,即表明採用定製排序
        if (cpr != null) 
        { 
            do { 
                // 使用 parent 上次迴圈後的 t 所引用的 Entry 
                parent = t; 
                // 拿新插入 key 和 t 的 key 進行比較
                cmp = cpr.compare(key, t.key); 
                // 如果新插入的 key 小於 t 的 key,t 等於 t 的左邊節點
                if (cmp < 0) 
                    t = t.left; 
                // 如果新插入的 key 大於 t 的 key,t 等於 t 的右邊節點
                else if (cmp > 0) 
                    t = t.right; 
                // 如果兩個 key 相等,新的 value 覆蓋原有的 value,
                // 並返回原有的 value 
                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 所引用的 Entry 
                parent = t; 
                // 拿新插入 key 和 t 的 key 進行比較
                cmp = k.compareTo(t.key); 
                // 如果新插入的 key 小於 t 的 key,t 等於 t 的左邊節點
                if (cmp < 0) 
                    t = t.left; 
                // 如果新插入的 key 大於 t 的 key,t 等於 t 的右邊節點
                else if (cmp > 0) 
                    t = t.right; 
                // 如果兩個 key 相等,新的 value 覆蓋原有的 value,
                // 並返回原有的 value 
                else 
                    return t.setValue(value); 
            } while (t != null); 
        } 
        // 將新插入的節點作為 parent 節點的子節點
        Entry<K,V> e = new Entry<K,V>(key, value, parent); 
        // 如果新插入 key 小於 parent 的 key,則 e 作為 parent 的左子節點
        if (cmp < 0) 
            parent.left = e; 
        // 如果新插入 key 小於 parent 的 key,則 e 作為 parent 的右子節點
        else 
            parent.right = e; 
        // 修複紅黑樹
        fixAfterInsertion(e);                              
        size++; 
        modCount++; 
        return null; 
    }
    

    ​ 2.1第一次添加時,把 k-v 封裝到Entry對象中,並放入root

    // 先以 t 保存鏈表的 root 節點
        Entry<K,V> t = root; 
        // 如果 t==null,表明是一個空鏈表,即該 TreeMap 里沒有任何 Entry 
        if (t == null) 
        { 
            // 將新的 key-value 創建一個 Entry,並將該 Entry 作為 root 
            root = new Entry<K,V>(key, value, null); 
            // 設置該 Map 集合的 size 為 1,代表包含一個 Entry 
            size = 1; 
            // 記錄修改次數為 1 
            modCount++; 
            return null; 
        } 
    

    ​ 2.2 之後的添加:

      Comparator<? super K> cpr = comparator; 
        // 如果比較器 cpr 不為 null,即表明採用定製排序
        if (cpr != null) 
        { 
            do { 
                // 使用 parent 上次迴圈後的 t 所引用的 Entry 
                parent = t; 
                // 拿新插入 key 和 t 的 key 進行比較
                cmp = cpr.compare(key, t.key); 
                // 如果新插入的 key 小於 t 的 key,t 等於 t 的左邊節點
                if (cmp < 0) 
                    t = t.left; 
                // 如果新插入的 key 大於 t 的 key,t 等於 t 的右邊節點
                else if (cmp > 0) 
                    t = t.right; 
                // 如果兩個 key 相等,新的 value 覆蓋原有的 value,
                // 並返回原有的 value 
                else 
                    return t.setValue(value); 
            } while (t != null); 
        } 
    

    思考:重寫了compareTo方法之後,現在比較的是key的長度。如果在treeMap集合中加入K-V,該key與集合中的某個key長度相同,結果會如何?

    答案:key不會被替換,但是value值會被最新的替換

    image-20220825184335003

20.Collections工具類

20.1排序

  1. Collections是一個提供操作Set、List和Map等集合的工具類
  2. Collections中提供了一系列靜態的方法,對集合元素進行排序、查詢和修改等操作
  • 排序操作:

    • reverse(List):反轉List中元素的順序

    • shuffle(List):對List集合元素進行隨機排序

    • sort(List):根據元素的自然順序對指定List集合元素進行升序排序

    • sort(List,Comparator):根據指定的Comparator產生的順序對List集合元素進行排序

    • swap(List,int,int):將制定List集合中的 i 處元素和 j 處元素進行交換

排序操作例子:

package li.collection.collectionskit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@SuppressWarnings("all")
public class Collections_ {
    public static void main(String[] args) {

        //創建一個ArrayList集合用於測試
        List list = new ArrayList();
        list.add("tom");
        list.add("smith");
        list.add("king");
        list.add("milan");

        //- reverse(List):反轉List中元素的順序
        Collections.reverse(list);
        System.out.println("reverse:" + list);//[milan, king, smith, tom]

        
        //- shuffle(List):對List集合元素進行隨機排序
        Collections.shuffle(list);
        System.out.println("shuffle:" + list);//每一次輸出的順序都不一樣

        
        //- sort(List):根據元素的自然順序對指定List集合元素進行升序排序
        Collections.sort(list);
        System.out.println("自然排序後" + list);//自然排序是按照字元串的大小來排的
        
        
        //- sort(List,Comparator):根據指定的Comparator產生的順序對List集合元素進行排序
        //指定排序規,例如希望按照字元串的長度大小來排序
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o1).length() - ((String) o2).length();
            }
        });
        //註意這裡可以輸出字元串長度相同的字元,因為是list,允許重覆,不用比較key
        System.out.println("按字元串長度大小排序:" + list);//按照字元串長度大小排序:[tom, king, milan, smith]
        
        
        //- swap(List,int,int):將制定List集合中的 i 處元素和 j 處元素進行交換
        Collections.swap(list,1,3 );
        System.out.println("交換後的排序:"+list);

    }
}
image-20220825205532225

20.2查找、替換

  1. Object max(Collection):根據元素的自然順序,返回給定集合中的最大元素
  2. Object max(Collection,Comparator):根據Comparator指定的順序,返回給定集合中的最大元素
  3. Object min(Collection):根據元素的自然順序,返回給定集合中的最小元素
  4. Object min(Collection,Comparator):根據Comparator指定的順序,返回給定集合中的最小元素
  5. int frequency(Collection,Object):返回指定集合中指定元素的出現次數
  6. void copy(List dest,List src):將src中的內容複製到dest中
  7. boolean replaceAll(List list,Object oldVal,Object oldVal,Object newVal):使用新值替換List對象的所有舊值

例子:

package li.collection.collectionskit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@SuppressWarnings("all")
public class Collections_ {
    public static void main(String[] args) {

        //創建一個ArrayList集合用於測試
        List list = new ArrayList();
        list.add("tom");
        list.add("smith");
        list.add("king");
        list.add("milan");


        //1. Object max(Collection):根據元素的自然順序,返回給定集合中的最大元素
        System.out.println("自然順序最大元素:" + Collections.max(list));//自然順序最大元素:tom


        //2. Object max(Collection,Comparator):根據Comparator指定的順序,返回給定集合中的最大元素
        //比如返回長度最大的元素
        Object maxObject = Collections.max(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o1).length() - ((String) o2).length();
            }
        });
        System.out.println("長度最大的元素:"+maxObject);//長度最大的元素:smith


        //3. Object min(Collection):根據元素的自然順序,返回給定集合中的最小元素
        System.out.println("自然順序最小元素:" + Collections.min(list));//自然順序最小元素:king


        //4. Object min(Collection,Comparator):根據Comparator指定的順序,返回給定集合中的最小元素
        //比如返回長度最大的元素
        Object minObject = Collections.min(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o1).length() - ((String) o2).length();
            }
        });
        System.out.println("長度最小的元素:"+minObject);//長度最小的元素:tom


        //5. int frequency(Collection,Object):返回指定集合中指定元素的出現次數
        System.out.println(""+Collections.frequency(list,"tom"));// 1


        //6. void copy(List dest,List src):將src中的內容複製到dest中
        //拷貝:註意如果要拷貝的集合大於新的集合,就會拋出異常--Source does not fit in dest
        //因此我們需要先給dest賦值,使元素個數和 list.suze()一樣
        ArrayList dest = new ArrayList();
        for (int i = 0; i < list.size(); i++) {
            dest.add("");
        }
        Collections.copy(dest,list);
        System.out.println("dest:"+dest);//dest:[tom, smith, king, milan]


        //7. boolean replaceAll(List list,Object oldVal,Object oldVal,Object newVal):使用新值替換List對象的所有舊值
        //例如,如果集合中有tom,就替換成 湯姆
        Collections.replaceAll(list,"tom","湯姆");
        System.out.println("替換後:"+list);//替換後:替換後:[湯姆, smith, king, milan]

    }
}
image-20220825213121594
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 01_Linux基礎-部署-VMware-Xshell-Xftp-內核-安迪比爾定理 博客🔗:https://blog.csdn.net/cpen_web CentOS開源 免費 ==CentOS是Linux里的開源免費版本== 一. 配置虛擬機 1. 新建虛擬機 2. 放 鏡像文件 鏡像文件其實 ...
  • Silver Efex Pro是您將使用的最先進的黑白照片插件。憑藉其獨特的演算法以及一系列用於亮度,對比度和放大白色等變化的工具和調整,Silver Efex Pro 3可以藉助最全面的暗房風格控制項來掌握黑白攝影藝術,為大家帶來了20種不同的黑白傳奇電影效果。 詳情:Silver Efex Pro ...
  • 想要全方位的實現HDR增強效果小編推薦使用HDR Efex Pro 2 Mac版,這是一款一款全新的高動態(HDR)成像解決方案,內置33種HDR效果,用戶可在右側HDR進行細節微調,強大簡便。 詳情:HDR Efex Pro 2 for mac(HDR濾鏡軟體) Hdr Efex Pro2是一款全 ...
  • 很多小伙伴不知道Color Efex Pro 4是用來幹嘛的,小編給大家介紹一下,Color Efex Pro 4 for Mac全球最全面,最有創意的濾鏡組,用於色彩校正,潤飾和應用最令人驚嘆和最富想象力的攝影效果,釋放最大的創造力和想象力。 詳情:Color Efex Pro 4 for Mac ...
  • 1. 關聯關係 1.1 關聯關係概念說明 表與表之間的關係 : 1 對 1 1對多 多對多關係 ,通過主外鍵來實現。 外鍵在多的一方。比如員工和部門: 1個員工對應一個部門,一個部門可以有多個員工 要將表與表之間的關係:映射稱為 類與類之間的關係(準確的說應該是 對象和對象之間的關係 ) 一對一 夫 ...
  • 學習Stream的目的 函數式編程漸漸變成主流,為了看懂同事的代碼。 相對於傳統的編程方式,代碼更為簡潔清晰易懂。 使得併發編程變得如此簡單。 有效的避免了代碼嵌套地獄。(見樣例) if (條件1) { if (條件2) { if (條件3) { // 再嵌套下去都快見到Diablo了。 } } } ...
  • 目錄 一.OpenGL 波浪特效效果演示 1.原始圖片 2.效果演示 二.OpenGL 波浪特效源碼下載 三.猜你喜歡 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目 ...
  • ##redis是什麼? Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。 redis是一個key-value存儲系統。和Memcached ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...