C#中的泛型集合全部歸結在System.Collections.Generic命名空間下。說起泛型集合,相信大家用到的最多的就是List<T>和 Dictionary<T1, T2> 這兩個吧,反正本人用的最多的就是這兩個,只要一想到泛型集合,就是二選一,也從來沒有考慮過是不是適合。後來仔細想了一下感覺哪裡不對,如果這兩個可以滿足任何需求的,.net裡就沒有必要弄那麼一大堆集合類了。雖然上面兩種集合可以滿足平時的需求,但是感覺以後還是要根據場合挑選一下再用,這畢竟也是個好的習慣,至少也要了解一下這麼多集合都是干什麼的。
讓我們先來看一下命名空間下大概都有哪些集合類,在MSDN中我們可以看到大概有一下幾個類表示泛型集合:
除卻最後三個關於線程安全的不講,剩下的有:
Dictionary<TKey, TValue> 、HashSet<T> 、LinkedList<T> 、List<T> 、 Queue<T> 、 SortedDictionary<TKey, TValue> 、 SortedList<TKey, TValue> 、 SortedSet<T> 、 Stack<T> 共九個。
我們一個個簡單說一下。
1、Dictionary<TKey,TValue>
這是一個鍵值集合,是鍵值集合中使用最多的一個類。這個集合最大的優點就是通過鍵值插入、刪除和查詢操作,是在這幾個集合中最快的一個(接近於O(1)),這全都得益於它是作為一個哈希表來實現的;其缺點就是由於是通過哈希的形式存儲,所以表中的數據是無序的,你並不能通過一定的順序遍歷表中的數據。
注意事項:(1)如果一個類型被用作鍵值的類型,那麼這個類型必須實現GetHashCode() 和 Equals() 方法,因為要被哈希,並且該類型提供的哈希算法的質量決定了通過鍵值操作集合的運算復雜度, 你最好還好實現IEqualityComparer 接口用做鍵值比較,否則將會使用默認比較器。(2)鍵的值必須唯一,且不能為null,除非Tvalue為引用類型。
總結:當你維護的一個集合不要求排序,而主要用來插入、刪除和查詢的話,推薦使用此集合。
2、SortedDictionary<TKey,TValue>
這個集合在使用上和Dictionary<TKey,TValue>很相似,但是在實現上大不相同。這個集合是遍歷一個運算復雜度為O(log n)的二叉搜索樹,而不是哈希表,其中n是元素的個數。這個集合會在列表變更的時候做一次排序操作。與SortedList<TKey,TValue>相比,優點是可對未排序的數據執行更快的插入和刪除操作(O(log n));缺點是使用的內存比SortedList<TKey,TValue>多,並且如果使用排序數據一次性填充列表,則 SortedList<TKey, TValue> 比 SortedDictionary<TKey, TValue> 快。
注意事項:(1)如果一個類型被用作鍵值的類型,則此類型要實現IComparer<T> ,因為要比較鍵值進行排序 ,都則會用默認的比較器。(2)鍵的值必須唯一,且不能為null,除非TValue為引用類型。
總結:當你要維護一個集合按一定規則排序時(初始如果是未排序的),並且會頻繁用來插入、刪除或查詢的話,推薦使用此集合。
3、SortedList<TKey,TValue>
和SortedDictionay<TKey,TValue>想是,也是一個根據鍵值進行排序的鍵值對,但是這個遍歷的是一個復雜度為O(log n)的數組,n是元素的個數。與SortedDictionary<TKey,TValue>相比,其優點是占用內存較少,使用排序數據一次性填充列表比SortedDictionary<TKey,TValue>快,並且SortedList<TKey, TValue> 支持通過由 Keys 和 Values 屬性返回的集合對鍵和值執行高效的索引檢索。 訪問此屬性時無需重新生成列表,因為列表只是鍵和值的內部數組的包裝。;缺點是對於插入和刪除操作,會相對慢一些(O(n)),因為它遍歷的是一個數組,但是對於查詢,復雜度和SortedDictionary<TKey,TValue>是一樣的。
注意事項:(1)如果一個類型被用作鍵值的類型,則此類型要實現IComparer<T> ,因為要比較鍵值進行排序 ,都則會用默認的比較器。(2)鍵的值必須唯一,且不能為null,除非TValue為引用類型。
總結:當你要維護一個集合按一定規則排序時(初始如果是排序的),並且只會頻繁的查詢,而很少插入和刪除的話,推薦使用此集合。
4、List<T>
大小按需動態增加的數組,是ArrayList的泛型實現。List<T> 類即使用相等比較器又使用排序比較器。諸如 Contains、IndexOf、LastIndexOf 和 Remove 這樣的方法對列表元素使用相等比較器。 類型 T 的默認相等比較器按如下方式確定。 如果類型 T 實現 IEquatable<T> 泛型接口,則相等比較器為該接口的 Equals(T) 方法;否則,默認相等比較器為 Object.Equals(Object)。 諸如 BinarySearch 和 Sort 這樣的方法對列表元素使用排序比較器。 類型 T 的默認比較器按如下方式確定。如果類型 T 實現 IComparable<T> 泛型接口,則默認比較器為該接口的 CompareTo(T) 方法;否則,如果類型 T 實現非泛型 IComparable 接口,則默認比較器為該接口的 CompareTo(Object) 方法。 如果類型 T 沒有實現其中任一個接口,則不存在默認比較器,並且必須顯式提供比較器或比較委托。 List<T> 不保證是排序的。在執行要求 List<T> 已排序的操作(例如 BinarySearch)之前,您必須對 List<T> 進行排序。需要注意的是,因為這個是一個數組,所以其對插入和刪除這類的操作效率並不高,但是對查詢的效率是很快的,所以使用這個最好不要頻繁插入刪除數據。
5、HashSet<T>
這是一組值的集合,提供高性能的集運算,裡面是一組不重復出現且無特定儲存順序的元素。 它主要的優勢就是運算快,所以對於沒有排序要求的情況下,推薦使用這個。
6、LinkedList<T>
這個是雙向鏈表(貌似沒有單鏈表)。插入和移除的運算復雜度為 O(1)。可以移除節點,然後在同一列表或其他列表中重新插入它們,這樣在堆中便不會分配額外的對象。 由於該列表還維護內部計數,因此獲取 Count 屬性的運算復雜度為 O(1)。 LinkedList<T> 接受 null 作為引用類型的有效 Value 屬性,並且允許重復值。 如果 LinkedList<T> 為空,則 First 和 Last 屬性為 null。
7、Queue<T>
表示先進先出的隊列集合。Queue<T> 的容量是 Queue<T> 可以包含的元素數。 當向 Queue<T> 中添加元素時,將通過重新分配內部數組來根據需要自動增大容量。Queue<T> 接受 null 作為引用類型的有效值並且允許有重復的元素。一般用於消息處理。
8、SortedSet<T>
這是一個排序的集合對象,當對象插入和刪除的時候,排序操作是不影響其性能的。其中的元素不可重復。但要注意,這個是在4.0版本中才加入的。
9、Stack<T>
表示先進後出的集合,即棧。Stack<T> 作為數組來實現。Stack<T> 的容量是 Stack<T> 可以包含的元素數。 當向 Stack<T> 中添加元素時,將通過重新分配內部數組來根據需要自動增大容量。如果 Count 小於堆棧的容量,則 Push 的運算復雜度是 O(1)。 如果需要增加容量以容納新元素,則 Push 的運算復雜度成為 O(n),其中 n 為 Count。 Pop 的運算復雜度為 O(1)。 Stack<T> 接受 null 作為引用類型的有效值並且允許有重復的元素。