C#集合类型总结和性能分析
C#集合類型概述
集合是.NET FCL(Framework Class Library)中很重要的一部分。所有的集合類都繼承自IEnumerable。集合類總體可分為一下幾類:關聯/非關聯型集合,順序/隨機訪問集合,順序/無序集合,泛型/非泛型集合,線程安全集合。
各集合類底層接口關系圖
泛型與非泛型集合類的分析
具體接口/類分析
CollectionBase/DictionaryBase的目的
IEnumerator/IEnumerable
IEnumerator定義了我們遍歷集合的基本方法,以便我們可以實現單向向前的訪問集合中的每一個元素。?所有的集合類都繼承了IEnumerator接口,包括String類。而IEnumerable只有一個方法GetEnumerator即得到遍歷器。
ICollection<T>和ICollection
從最上面第一張圖我們可以知道,ICollection是直接繼承自IEnumerable。而實際上也是如此,我們可以說ICollection比IEnumerable多支持一些功能,不僅僅只提供基本的遍歷功能,還包括:
統計集合和元素個數?
獲取元素的下標?
判斷是否存在?
添加元素到未尾?
移除元素等等。。。?
ICollection 與ICollection<T> 略有不同,ICollection不提供編輯集合的功能,即Add和Remove。包括檢查元素是否存在Contains也不支持。
IList和IList
IList則是直接繼承自ICollection和IEnumerable。所以它包括兩者的功能,并且支持根據下標訪問和添加元素。IndexOf, Insert, RemoveAt等等。我們可以這樣說,IEnumerable支持的功能最少,只有遍歷。而ICollection支持的功能稍微多一點,不僅有遍歷還有維護這個集合的功能。而IList是最全的版本。
IReadOnlyList<T>
這個是在Framework4.5中新增的接口類型,可以被看作是IList的縮減版,去掉了所有可能更改這個集合的功能。比如:Add, RemoveAt等等。
IDictionary<TKey,TValue>
IDictionary提供了對鍵值對集合的訪問,也是繼承了ICollection<T>和IEnumerable,擴展了通過Key來訪問和操作數據的方法。
關聯性泛型集合類
關聯性集合類即我們常說的鍵值對集合,允許我們通過Key來訪問和維護集合。我們先來看一下 FCL為我們提供了哪些泛型的關聯性集合類:
Dictionary <TKey,TValue>?
SortedDictionary<TKey,TValue>?
SortedList<TKey,TValue>?
Dictionary<TKey,TValue>
Dictionary<TKey,TValue>
是我們最常用的關聯性集合了,它的訪問,添加,刪除數據所花費的時間是所有集合類里面最快的,因為它內部用了Hashtable作為存儲結構,所以不管存儲了多少鍵值對,查詢/添加/刪除所花費的時間都是一樣的,它的時間復雜度是O(1)。
Dictionary<TKey,TValue>優勢是查找插入速度快,那么什么是它的劣勢呢?因為采用Hashtable作為存儲結構,就意味著里面的數據是無序排列的,所以想按一定的順序去遍歷Dictionary<TKey,TValue>里面的數據是要費一點工夫的。
作為TKey的類型必須實現GetHashCode()和Equals() 或者提供一個IEqualityComparer,否則操作可能會出現問題。
SortedDictioanry<TKey,TValue>
SortedDictionary<TKey,TValue>和Dictionary<TKey,TValue>大致上是類似的,但是在實現方式上有一點點區別。SortedDictionary<TKey,TValue>用二叉樹作為存儲結構的。并且按key的順序排列。那么這樣的話SortedDictionary<TKey,TValue>的TKey就必須要實現IComparable<TKey>。如果想要快速查詢的同時又能很好的支持排序的話,那就使用SortedDictionary吧。
SortedList<TKey,TValue>
SortedList<TKey,TValue>是另一個支持排序的關聯性集合。但是不同的地方在于,SortedList實際是將數據存存儲在數組中的。也就是說添加和移除操作都是線性的,時間復雜度是O(n),因為操作其中的元素可能導致所有的數據移動。但是因為在查找的時候利用了二分搜索,所以查找的性能會好一些,時間復雜度是O(log n)。所以推薦使用場景是這樣地:如果你想要快速查找,又想集合按照key的順序排列,最后這個集合的操作(添加和移除)比較少的話,就是SortedList了。
非關聯性泛型集合類
非關聯性集合就是不用key操作的一些集合類,通常我們可以用元素本身或者下標來操作。FCL主要為我們提供了以下幾種非關聯性的泛型集合類。
List<T>?
LinkedList<T>?
HashSet<T>?
SortedSet<T>?
Stack<T>?
Queue<T>?
List<T>
泛型的List 類提供了不限制長度的集合類型,List在內部維護了一定長度的數組(默認初始長度是4),當我們插入元素的長度超過4或者初始長度 的時候,會去重新創建一個新的數組,這個新數組的長度是初始長度的2倍(不永遠是2倍,當發現不斷的要擴充的時候,倍數會變大),然后把原來的數組拷貝過來。所以如果知道我們將要用這個集合裝多少個元素的話,可以在創建的時候指定初始值,這樣就避免了重復的創建新數組和拷貝值。
另外的話由于內部實質是一個數組,所以在List的未必添加數據是比較快的,但是如果在數據的頭或者中間添加刪除數據相對來說更低效一些因為會影響其它數據的重新排列。
LinkedList<T>
LinkedList在內部維護了一個雙向的鏈表,也就是說我們在LinkedList的任何位置添加或者刪除數據其性能都是很快的。因為它不會導致其它元素的移動。一般情況下List已經夠我們使用了,但是如果對這個集合在中間的添加刪除操作非常頻繁的話,就建議使用LinkedList。
HashSet<T>
HashSet是一個無序的能夠保持唯一性的集合。我們也可以把HashSet看作是Dictionary<TKey,TValue>,只不過TKey和TValue都指向同一個對象。HashSet非常適合在我們需要保持集合內元素唯一性但又不需要按順序排列的時候。
HashSet不支持下標訪問。
SortedSet<T>
SortedSet和HashSet,就像SortedDictionary和Dictionary一樣,還記得這兩個的區別么?SortedSet內部也是一個二叉樹,用來支持按順序的排列元素。
Stack<T>
后進先出的隊列?
不支持按下標訪問
Queu<T>
先進先出的隊列?
不支持按下標訪問
推薦使用場景
非泛型類集合
泛型集合類是在.NET2.0的時候出來的,也就是說在1.0的時候是沒有這么方便的東西的。現在基本上我們已經不使用這些集合類了,除非在做一些和老代碼保持兼容的工作的時候。來看看1.0時代的.NET程序員們都有哪些集合類可以用。
ArraryList?
后來被List<T>替代。
HashTable 后來被Dictionary<TKey,TValue>替代。?
Queue 后來被Queue<T>替代。?
SortedList 后來被SortedList<T>替代。?
Stack 后來被Stack<T>替代。
線程安全的集合類
ConcurrentQueue 線程安全版本的Queue?
ConcurrentStack線程安全版本的Stack?
ConcurrentBag線程安全的對象集合?
ConcurrentDictionary線程安全的Dictionary?
BlockingCollection
.NET為我們提供的集合類是我們很常用的工具類之一,希望這篇文章能夠幫助大家更好的認識這些集合類。當然,個人感覺還有不完善的地方,比如說HashTable和Binary Search Tree就沒有細究下去,包括單向鏈表和雙向鏈表之間的對比本文也沒有提及。感興趣的朋友可以深入了解一下。
總結
以上是生活随笔為你收集整理的C#集合类型总结和性能分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 七彩虹电竞一体机iGame G-ONE
- 下一篇: 《饥饿游戏》前传成情侣档:“白雪公主”和