Java-TreeMap和Guava-HashMultiset

守林鳥發表於2021-03-25

一、Java-TreeMap

1.資料結構

底層資料結構是裸的紅黑樹,保證元素有序,沒有比較器Comparator的情況按照key的自然排序,可自定義比較器。執行緒不安全。

可以存null,但是key不可以為null。

2.效能分析:空間換時間

增刪改查的時間複雜度都是O(log n),HashMap的時間複雜度則是O(1),但是相比HashMap,TreeMap沒有多餘的空間,也沒有負載因子。

2.幾個查詢方法

  • boolean containsValue(Object value):判斷該TreeMap中是否包含有關指定value的對映
  • Map.Entry<K, V> firstEntry():返回該TreeMap的第一個(最小的)對映
  • K firstKey():返回該TreeMap的第一個(最小的)對映的key
  • Map.Entry<K, V> lastEntry():返回該TreeMap的最後一個(最大的)對映
  • K lastKey():返回該TreeMap的最後一個(最大的)對映的key
  • SortedMap<K, V> headMap(K toKey):返回該TreeMap中嚴格小於指定key的對映集合
  • SortedMap<K, V> subMap(K fromKey, K toKey):返回該TreeMap中指定範圍的對映集合(大於等於fromKey,小於toKey)
  • Object ceilingKey(Object key);返回大於或等於給定鍵的最小鍵,如果沒有這樣的鍵則返回null
  • Object higherKey(Object key);返回嚴格大於指定鍵的最小鍵,沒有則返回null
3.遍歷
for (Map.Entry entry : treeMap.entrySet()) {
      System.out.println(entry);
}
Iterator iterator = treeMap.entrySet().iterator();
while (iterator.hasNext()) {
      System.out.println(iterator.next());
}

4.刷題殺招

  • Object ceilingKey(Object key);返回大於或等於給定鍵的最小鍵,如果沒有這樣的鍵則返回null
  • Object higherKey(Object key);返回嚴格大於指定鍵的最小鍵,沒有則返回null
  • V getOrDefault(Object key, V defaultValue); 如果存在value則返回value,如果沒有則返回defaultValue

map.put(key, map.getOrDefault(key,0)+1); 若有key則返回key的數量,如果沒有則返回0,put的時候設定為1,達到對key計數的效果,相當於維護一個有序、可重複集合

 
5.例題
題意:有一個長度為104的陣列a,元素大小為109,判斷有沒有這樣的子序列:i<j<k && a[i]<a[k]<a[j]
思路:遍歷陣列,將遍歷到的每個數當作a[j]處理。
在遍歷的過程中,去左邊找a[i],去右邊找a[k],首先滿足第一個條件,索引i<j<k;
左邊[0,j-1]找a[i],是最小值,那就在j遍歷的過程中維護最小值;
右邊[j+1,n-1]找a[k],是次小值,那麼就找比a[i]大一點點即可,再與a[j]比較,右邊維護一個有序集合,方便快速找值;
陣列元素是109級別,不能用陣列計數,則需要用map對映,沒有說不重複,則需要計數,顯然可以維護一個有序、可重複集合。
    /** 456. 132模式
     * 求是否存在子序列a[i],a[j],a[k]
     * i<j<k
     * a[i]<a[k]<a[j]
     * n<1e4  a[i]<1e9
     * 遍歷陣列,將遍歷到的每個數當a[j]處理
     * 不看陣列元素大小,只要遍歷到的數在中間,就先滿足了下標
     * 左邊[0,j-1]是判斷a[i]的,a[i]是最小的,那麼就維護一個最小值
     * 右邊[j+1,n-1]是判斷a[k]的,a[k]是次小值,那就找比a[i]大一點點即可,再與a[j]比較
     */
    public boolean find132pattern(int[] a) {
        int n=a.length;
        if(n<3)
            return false;
        int minn=a[0];
        TreeMap<Integer,Integer> map=new TreeMap<>();
        for(int k=2;k<n;k++){
            map.put(a[k], map.getOrDefault(a[k],0)+1);
            /**
             * map.getOrDefault(a[k],0)表示,如果a[k]存在就返回a[k]的值,否則返回0
             *一開始必然是返回0,設定value為1,隨後逐漸增多,達到計數效果
             */
        }
        Integer ak=null;
        for(int j=1;j<n-1;j++){
            if(minn<a[j]){
                ak=map.higherKey(minn);
                if(ak!=null &&  ak<a[j]){
                    return true;
                }
            }
            minn=Math.min(minn,a[j]);
            if(map.get(a[j+1])==1){
                map.remove(a[j+1]);
            }else{
                map.put(a[j+1],map.get(a[j+1])-1);
            }
        }
        return false;
    }

 

 

二、Guava-HashMultiset

參考:https://www.cnblogs.com/qdhxhz/p/9410898.html

Guava是Goolge的庫,不是jdk的,補充了一些集合類功能的不足。

1.先匯入依賴包

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>27.0-jre</version>
        </dependency> 

2.Multiset用法

Multiset是一個介面,沒有實現java.util.Set介面,Set規定不可以放入相同元素,如果放入相同元素會被覆蓋,Multiset相對於Set,可以新增相同元素。 

  • Multiset<Integer> set = HashMultiset.create();//建立方式不是用new
  • add(E e)//新增一個元素e
  • add(E e, int x)//新增x個元素e
  • remove(E e)//刪除一個元素e
  • remove(E e, int x)//刪除x個元素e
  • elementSet()//將不同的元素放入一個Set中
  • count(E e)//返回元素e的個數
  • setCount(E e ,int x)//指定集合裡有x個元素e
  • setCount(E e,int x,int y)//如果恰好有x個e,則變為y,否則方法無效
  • retainAll(Collection c)//保留出現在給定集合引數的所有的元素,其他都不要
  • removeAll(Collection c)//去除出現給給定集合引數的所有的元素,有就去掉,沒有不用管
  • size()//所有元素總個數

3.常用的實現了Multiset 介面的類

  • HashMultiset: 元素存放於 HashMap(決定了無序性
  • LinkedHashMultiset: 元素存放於 LinkedHashMap,即元素的排列順序由第一次放入的順序決定
  • TreeMultiset:元素被排序存放於TreeMap
  • EnumMultiset: 元素必須是 enum 型別
  • ImmutableMultiset: 不可修改的 Mutiset 

4.遍歷

        System.out.println("--遍歷全部元素,包括重複的---");
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("--只遍歷key,不重複---");
        for(Integer key: set.elementSet()){
            System.out.println("key="+key+" cnt="+set.count(key));
        }

 

相關文章