鸠合是.NET FCL(Framework Class Library)中很主要的一部分,也是我们开辟当中最经常运用到的功用之一,几乎是无处不在。俗语说知其然,知其所以然,寻常看到IEnumerable,IEnumerator,ICollection是不是是晓得他们之间各自的区分?除了List和Dictionary之外,你还用过哪些别的的鸠合类?废话少说,本日我们就来看一些这些定义鸠合类的接口以及他们的完成。
鸠合接口
先来看一下,FCL为我们供应了哪些接口:
IEnumerable 和IEnumberator
public interface IEnumerator { bool MoveNext(); object Current { get; } void Reset(); }
IEnumerator定义了我们遍历鸠合的基础要领,以便我们可以完成单向向前的接见鸠合中的每个元素。而IEnumerable只要一个要领GetEnumerator即获得遍历器。
public interface IEnumerable { IEnumerator GetEnumerator(); }
注重:我们经经常运用的foreach等于一种语法糖,现实上照样挪用Enumerator内里的Current和MoveNext完成的遍历功用。
List<string> list = new List<string>() { "Jesse", "Chloe", "Lei", "Jim", "XiaoJun" }; // Iterate the list by using foreach foreach (var buddy in list) { Console.WriteLine(buddy); } // Iterate the list by using enumerator List<string>.Enumerator enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); }
上面的代码中用到的foreach和enumerator到IL中末了都会被翻译成enumerator的MoveNext和Current。
IEnumerable是一个很有效的接口,完成它的优点包含:
支撑foreach语句
作为一个规范的鸠合类与别的类库举行交互
满足更庞杂的鸠合接口的需求
支撑鸠合初始化器
固然完成的要领也有许多,以下:
假如我们鸠合是经由过程封装别的鸠合类而来的,那末我们可以直接返回这个鸠合的enumerator
经由过程yield return 来返回
完成我们自身的IEnumerator来完成
这里给人人演示一下怎样经由过程yield来完成返回enumerator
public class BuddyList : IEnumerable { private string[] data= new string[] { "Jesse", "Chloe", "Lei", "Jim", "XiaoJun" }; public IEnumerator GetEnumerator() { foreach (var str in data) { yield return str; } } } var myBuddies= new BuddyList(); foreach (var str in myBuddies) { Console.WriteLine(str); }
ICollection<T>和ICollection
从最上面第一张图我们可以晓得,ICollection是直接继续自IEnumerable。而现实上也是云云,我们可以说ICollection比IEnumerable多支撑一些功用,不单单议只供应基础的遍历功用,还包含:
统计鸠合和元素个数
猎取元素的下标
推断是不是存在
增加元素到未尾
移除元素等等。。。
ICollection 与ICollection<T> 略有差别,ICollection不供应编辑鸠合的功用,即Add和Remove。包含搜检元素是不是存在Contains也不支撑。
IList<T>和IList
IList则是直接继续自ICollection和IEnumerable。所以它包含二者的功用,而且支撑依据下标接见和增加元素。IndexOf, Insert, RemoveAt等等。我们可以如许说,IEnumerable支撑的功用起码,只要遍历。而ICollection支撑的功用轻微多一点,不仅有遍历另有保护这个鸠合的功用。而IList是最全的版本。
IReadOnlyList<T>
这个是在Framework4.5中新增的接口范例,可以被看做是IList<T>的缩减版,去掉了一切可以变动这个鸠合的功用。比方: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>
先进先出的行列
不支撑按下标接见
引荐运用场景
鸠合 |
递次分列 |
连顺存储 |
直接接见体式格局 |
接见时刻 |
操纵时刻 |
备注 |
Dictionary |
|
是 |
Key |
Key: O(1)
|
O(1) |
接见机能最快,不支撑排序 |
SortedDinctionary |
递次分列 |
否 |
Key |
Key: |
O(log n) |
疾速接见和支撑排序的折中 |
SortedList |
递次分列 |
是 |
Key |
Key: O(log n)
|
O(n) |
和SortedDictionary类似,只是内部用数据替换树作为存储构造。 |
List |
运用者可以准确掌握元素的位置 |
是 |
Index |
Index: O(1) Value: O(n)
|
O(n) |
最适合须要直接接见每个元素的少许鸠合。 |
LinkedList |
运用者可以准确掌握元素的位置 |
否 |
不支撑 |
Value: O(n)
|
O(1) |
最适合不须要直接接见单个元素,然则在鸠合中增加/移除异常频仍的场景。 |
HashSet |
不支撑 |
是 |
Key |
Key: O(1)
|
O(1) |
能坚持元素唯一性的鸠合。不支撑排序 |
SortedSet |
递次分列 |
否 |
Key |
Key: O(log n)
|
O(log n) |
能坚持元素唯一性而且支撑排序。 |
Stack |
LIFO |
是 |
只能猎取顶部元素 |
Top: O(1) |
O(1) |
|
Queue |
FIFO |
是 |
只能获底部元素 |
Front: O(1) |
O(1) |
|
非泛型类鸠合
泛型鸠合类是在.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#鸠合范例大清点的图文代码的细致内容,更多请关注ki4网别的相干文章!