java基礎學習之十:集合型別Set/List/Map(TreeSet,LinkedList,TreeMap)

趙明威發表於2016-06-03

在Java基礎學習之九,我們學習了Set/List/Map的一部分(HashSet,ArrayList,HashMap),在本文,我們將學習剩下的常用的一些集合型別(TreeSet,LinkedList,TreeMap)

繼續貼出基本的集合繼承和實現的關係圖

集合繼承實現關係圖

一、TreeMap

由於基礎性的關係,先說說TreeMap

public class TreeMap<K,V> extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
//TreeMap的一個建構函式
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}
  • TreeMap 是一個有序的key-value集合
  • TreeMap 繼承了AbstractMap,TreeMap是一個Map
  • TreeMap的一個建構函式,允許我們通過自己定義排序方式,預設排序方式是按照自然順序

TreeMap的基本的方法和HashMap一致(但是有序的)在此只列舉出來一些方法:具體的不再詳細介紹

    TreeMap<String,Integer> treeMap = new TreeMap<>();
    treeMap.put("apple",2);
    treeMap.put("pear",8);
    treeMap.put("banana", 12);

    System.out.println(treeMap.get("apple"));//2  根據某個key 取value
    System.out.println(treeMap.containsKey("banana"));// true 判斷是否存在某個key
    System.out.println(treeMap.containsValue(12));//true  判斷是否存在某個value

遍歷方式:遍歷出來的結果是對key的一個自然排序,即字母的先後順序來排序

    //遍歷方式>1
    for (Map.Entry entry : treeMap.entrySet()){
        System.out.println(entry.getKey()+":"+entry.getValue());
    }

    System.out.println("=============");
   //遍歷方式>2
   for (String key : treeMap.keySet()){
       System.out.println(key+":"+treeMap.get(key));
   }

結果:

2
true
true
apple:2
banana:12
pear:8
=============
apple:2
banana:12
pear:8
============

對treeMap的自定義排序

對key進行排列

    TreeMap<String,Integer> treeMap = new TreeMap<>(
        new Comparator<String>() {
            public int compare(String obj1, String obj2) {
                // 降序排序
                return obj2.compareTo(obj1); //obj1.compareTo(obj2); 升序
            }
        });

結果:

pear:8
banana:12
apple:2

對value進行排列(網上流傳很廣的做法)

//自定義一個比較器
class myComparator implements Comparator<Map.Entry<String,Integer>>{
public int compare(Map.Entry<String, Integer> o1,
                   Map.Entry<String, Integer> o2) {
    return o1.getValue()-o2.getValue();
  }
}

 List<Map.Entry<String,Integer>> arrayList = 
           new ArrayList<Map.Entry<String,Integer>>(treeMap.entrySet());
    //給sort傳入一個Comparator例項,實現自定義排序,Comparator只是一個挽救的類(介面)
    Collections.sort(arrayList, new myComparator());
    for(Map.Entry<String,Integer> mapper: arrayList){
        System.out.println(mapper.getKey()+":"+mapper.getValue());
    }

結果:

apple:2
pear:8
banana:12

所以在不要求排序的情況下用Map,或者沒有排序需求的情況下用Map,儘量少用TreeMap,用HashMap


二、TreeSet

基本特性:

  • TreeSet 是一個有序的集合
  • TreeSet 繼承於AbstractSet,所以它是一個Set集合,具有Set的屬性和方法。
  • TreeSet是基於TreeMap實現的。這就是先要學習TreeMap的原因

效能根據stackoverflow 上的一篇文章:TreeSet VS HashSet

HashSet:

  1. 對於基本的操作(add, remove, contains and size)時間複雜度是個常數
  2. 它不能保證元素的順序將保持不變, 隨著時間的推移, 迭代的效能依賴於初始容量和負載因子。 接受預設的負載因子是相當安全的,但你可能要指定一個初始容量,大約是你期望的大小的兩倍.

TreeSet:

  1. 對於基本操作(add, remove, contains and size) 時間複雜度為log(n)
  2. 保證元素將排序(升序,自然的,或是由你指定的建構函式)(實現了SortedSet) 不提供任何調整引數的迭代效能,提供處理命令設定first(),last(),headset()一些方便的方法,和tailset()等
  3. 所以HashSet能快速的對元素進行操作, 在不要求順序的前提下你儘量使用HashSet

TreeSet預設按照自然順序:對首字母進行排序,首字母相同則按照第二個字母再排序

    TreeSet<String> treeSet = new TreeSet<>();
    treeSet.add("abc");
    treeSet.add("aac");
    treeSet.add("cac");
    treeSet.add("cbc");
    treeSet.add("bcc");
    treeSet.add("bbc");
    treeSet.add("bac");
    System.out.println(Arrays.toString(treeSet.toArray()));

結果:

[aac, abc, bac, bbc, bcc, cac, cbc]

自定義排序方式:

預設的排序方式和下面的方法一致:

    TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2);
        }
    });

如果是要降序排列的話:

    TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o2.compareTo(o1);
        }
    });

遍歷方法:

    System.out.println(Arrays.toString(treeSet.toArray()));

    for (String str : treeSet){
        System.out.println(str);
    }

    System.out.println("++++++++++++++");

    Iterator<String> iterator = treeSet.iterator();
    while (iterator.hasNext()){
        System.out.println(iterator.next());
    }

結果:

[aac, abc, bac, bbc, bcc, cac, cbc]
aac
abc
bac
bbc
bcc
cac
cbc
++++++++++++++
aac
abc
bac
bbc
bcc
cac
cbc

三、LinkedList

  1. ArrayList是實現了基於動態陣列的資料結構,LinkedList基於連結串列的資料結構。
  2. 對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指標。
  3. 對於新增和刪除操作add和remove,LinedList比較佔優勢,因為ArrayList要移動資料。

對於想深入瞭解LinkedList的同學可以參考:http://pengcqu.iteye.com/blog/502676

什麼時候該使用 ArrayList 什麼時候該使用LinkedList呢?

1.對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部陣列中增加一項,指向所新增的元素,偶爾可能會導致對陣列重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry物件。

2.在ArrayList的中間插入或刪除一個元素意味著這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。

3.LinkedList不支援高效的隨機元素訪問。

4.ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間

可以這樣說:當操作是在一列資料的後面新增資料而不是在前面或中間,並且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的效能;當你的操作是在一列資料的前面或中間新增或刪除資料,並且按照順序訪問其中的元素時,就應該使用LinkedList了。


最近申請了微信公眾號,希望大家來看看,專門為程式設計師而生,做最好的程式設計

高斯程式設計

相關文章