C#常用容器与底层

Array

最基本的数组。在内存中是连续存储的,索引速度非常快,而且赋值与修改元素很快也很简单。

不足之处:

在两个数组直接插值很麻烦,并且在声明的时候需要指定数组的长度。

ArrayList

动态数组,Array的加强版,底层也是数组,继承了IList接口。ArrayList对象的大小是按照其中存储的数据来动态扩充与收缩的。所以,在声明ArrayList对象时并不需要指定它的长度。

但是ArrayList会把所有插入其中的数据当作为object类型来处理,也就是说你可以在0号位置存int,1号位置存string,所以在我们使用ArrayList处理数据时,很可能会报类型不匹配的错误,也就是说ArrayList不是类型安全的。而且在存储或检索值类型的时候通常会发生装箱和拆箱操作,带来很大的性能消耗。

List

底层和ArrayList一样。因为ArrayList不是类型安全的且需要频繁的装箱拆箱,所以出现了泛型的概念。List是ArrayList的泛型等效类,大部分用法都与ArrayList相似,因为List也继承了IList接口。最关键的区别在于,在声明List的时候需要给List集合内部数据的对象一个类型。

LinkedList

相当于C++中的list,内部实现是双链表,插入删除快,查找慢。

在List中增加、删除节点的速度,大体上快于使用LinkedList时的相同操作。将 List.Add方法和LinkedList的Add方法相比较,真正的性能差别不在于Add操作,而在LinkedList在给GC(垃圾回收机制)的压力上。一个List本质上是将其数据保存在一个堆栈的数组上,而LinkedList是将其所有节点保存在堆栈上(人家是一个,我是一系列)。这就使得GC需要更多地管理堆栈上LinkedList的节点对象。注意,List.Insert方法比在LinkedList中使用Add*方法在任何地方添加一个节点可能要慢。然而,这个依赖于List插入对象的位置。Insert方法必须使所有在插入点后面的元素往后移动一位。如果新元素被插在List最后或接近最后的位置,那么相对于GC维护LinkedList节点的总的开销来说,其开销是可以被忽略的。

HashSet

底层是哈希表。HashSet 类提供了高性能的集运算。一组是一个集合,不包含任何重复的元素,且元素顺序不分先后。

用了hash table来储存数据,是为了用O(n)的space来换取O(n)的时间,也就是查找元素的时间是O(1)。

HashTable

底层也是哈希表。Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key/value的键值对,其中key通常可用来快速查找,同时key是区分大小写;value用于存储对应于key的值。Hashtable中key/value键值对均为object类型,所以Hashtable可以支持任何类型的key/value键值对,同理,也会有装箱和拆箱的性能消耗。

他内部维护很多对Key-Value键值对,其还有一个类似索引的值叫做散列值(HashCode),它是根据GetHashCode方法对Key通过一定算法获取得到的,所有的查找操作定位操作都是基于散列值来实现找到对应的Key和Value值的

当前HashTable中的被占用空间达到一个百分比的时候就将该空间自动扩容,在.net中这个百分比是72%,也叫.net中HashTable的填充因子为0.72。例如有一个HashTable的空间大小是100,当它需要添加第73个值的时候将会扩容此HashTable.

这个自动扩容的大小是多少呢?答案是当前空间大小的两倍最接近的素数,例如当前HashTable所占空间为素数71,如果扩容,则扩容大小为素数131.

Dictionary

相当于C++中的map。只不过map的内部实现是红黑树,Dictionary的内部实现是哈希表。他是类型安全的容器。在单线程的时候使用Dictionary更好一些,多线程的时候使用HashTable更好。

你可能感兴趣的:(C#常用容器与底层)