C#集合类型概述

集合是.NET FCL(Framework Class Library)中很重要的一部分。所有的集合类都继承自IEnumerable。集合类总体可分为一下几类:关联/非关联型集合,顺序/随机访问集合,顺序/无序集合,泛型/非泛型集合,线程安全集合。

各集合类底层接口关系图

泛型与非泛型集合类的分析

  1. 泛型集合是类型安全的,基于固定的泛型T,运行时不需要像非泛型的执行Object和具体类型的类型转换。
  2. 泛型集合的效率相对较高。
  3. 两者都能实现数据存储,不同的是泛型只能存放T类型数据,有运行时检测,而非泛型的都转化为Object存储,能存储任意类型,包括值类型,会带来装箱拆箱的性能损耗,同时都是Object类型(弱类型)编译时无法类型检测,运行时会导致类型不一致的安全性问题。

具体接口/类分析

CollectionBase/DictionaryBase的目的

  1. 都是抽象类,不能实例化;
  2. 目的是提供给用户自定义实现强类型的集合,解决一般非泛型集合的弱类型不安全的问题。

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#集合类型总结和性能分析相关推荐

  1. ue4集合类型_UE4.22 Subsystem分析

    2019年4月2日,UE4.22版本正式发布,其中包含了很多新的特性,Subsystem(子系统)便是其中之一,这篇文章将分析Subsystem的用法以及实现原理. 概述 Subsystem(子系统) ...

  2. Java 集合中的方法性能分析

    文章目录 前言 一.List集合 1.1.Collection 中 get() 和 remove()方法的效率 示例一 示例二 总结 前言 暂无 一.List集合 1.1.Collection 中 g ...

  3. 第41讲:MySQL内置的QL性能分析工具

    文章目录 1.SQL性能分析的概念 2.分析数据库中SQL的执行频率 3.数据库中的慢查询日志 3.1.开启慢查询日志功能 3.2.模拟慢SQL查询观察日志内容 4.Profile查看SQL每个阶段的 ...

  4. java集合性能_Java集合性能分析-疯狂Java讲义

    一.各Set实现类的性能分析 HashSet和TreeSet是Set的两个典型实现.HashSet的性能总是比TreeSet好(特别是最常用的添加.查询元素等操作),因为TreeSet需要额外的红黑树 ...

  5. Java集合性能分析-疯狂Java讲义

    一.各Set实现类的性能分析 HashSet和TreeSet是Set的两个典型实现.HashSet的性能总是比TreeSet好(特别是最常用的添加.查询元素等操作),因为TreeSet需要额外的红黑树 ...

  6. Java集合Set性能分析

    Set性能分析 HashSet 和 TreeSet HashSet性能要好于TreeSet(特别是最常用的添加.查询元素等操作) 原因:因为TreeSet需要额外的红黑树算法维护集合元素的次序.只有需 ...

  7. python利用集合的无重复性_python集合类型用法分析

    本文实例分析了python集合类型用法.分享给大家供大家参考.具体分析如下: python的集合类型和其他语言类似, 是一个无序不重复元素集,我在之前学过的其他的语言好像没有见过这个类型,基本功能包括 ...

  8. 使用gprof对程序的性能分析(集合贴)

    综述 gprof用于分析函数调用耗时,可用之抓出最耗时的函数,以便优化程序. gcc链接时也一定要加-pg参数,以使程序运行结束后生成gmon.out文件,供gprof分析. gprof默认不支持多线 ...

  9. DevTools 实现原理与性能分析实战

    作者:vivo 互联网浏览器内核团队-Li Qingmei 一.引言 从 2008 年 Google 释放出第一版的 Chrome 后,整个 Web 开发领域仿佛被注入了一股新鲜血液,渐渐打破了 IE ...

最新文章

  1. LeetCode简单题之石头与宝石
  2. 【干货】JDK动态代理的实现原理以及如何手写一个JDK动态代理
  3. S1系统相关-uptime命令总结(S代表系统相关,1代表第一个命令)
  4. 宜昌远安谋定功能性-农业大健康·万祥军:绿色和谐新路
  5. HTML DOM(一):认识DOM
  6. es 时间字段聚合_ES之五:ElasticSearch聚合
  7. 每天进步一点点《ML - DBSCAN》
  8. Python 正则表达式(二)
  9. 移动Web—CSS为Retina屏幕替换更高质量的图片
  10. 疫情之后,人工智能该如何走?
  11. Java写一个app控制电机_java控制步进电机
  12. C#知识点:操作XML
  13. lbj学习日记 04 循环和选择结构的刷题心得
  14. 计算机换色带技巧,平乐园电脑维修店教你爱普生针式打印机更换色带基本办法...
  15. 一位美国教授给研究生的怎样记读书笔记的建议(中文总结)
  16. getchar()作用
  17. BetaFlight统一硬件配置文件研读之set命令
  18. SpringBoot 事务管理
  19. vue+element下拉框实现二级联动
  20. VSCode 使用教程--配置 C / C++ 环境

热门文章

  1. SVG_text.动态创建换行显示(横)
  2. 20159206 《网络攻防实践》第九周学习总结
  3. leetcode 第五题 Longest Palindromic Substring (java)
  4. 一些有用的javascript实例分析(二)
  5. POJ-3693 Maximum repetition substring 后缀数组
  6. ASP.NET MVC Music Store教程(2):控制器
  7. golang 没有名字参数_Go 返回参数命名
  8. python基础公式_一、Python基础(数据类型、基本函数、基本运算)
  9. 蓝桥杯第六届C语言B——积分之谜
  10. Vue框架之条件与循环的使用