C# 集合的学习总结

以下是对最长用的集合进行简单的总结

集合说明
List<T>可以像数组一样按索引访问列表,但提供了其他方法来搜索和排序
Queue<T>先入先出数据结构,提供了方法将数据项添加到队列的一段,从另一端删除项,以及只检查不删除
Stack<T>先入后出数据结构,提供了方法将数据压入栈顶,从栈顶出栈,以及只检查栈顶的项而不删除
LinkedList<T>双向有序列表,为任何一端的插入和删除进行了优化,这种集合既可作为队列,也可作为栈,还支持列表那样的随机访问
HashSet<T>无序值列表,为快速数据获取而优化,提供了面向集合的方法来判断它容纳的项是不是另一个HashSet<T> 对象中的项的子集,以及计算不同HashSet<T> 对象的交集和并集
Dictionary<TKey,TValue>字典集合允许根据键而不是索引来获取值
SortedList<TKey,TValue>键/值对的有序列表,键必须实现Icomparable<T>接口

集合的基本信息:

  1. 非泛型集合的类和接口位于System.Collections命名空间。
  2. 泛型集合的类和接口位于System.Collections.Generic命名空间。
  3. 针对特定类型的集合类型位于System.Collections.Specialized;命名空间;
  4. 线程安全的集合类位于System.Collections.Concurrent;命名空间。

ICollection接口是System.Collections命名空间中非泛型集合类的基接口,它继承自IEnumerable接口,从IEnumerable接口继承意味着实现该接口的实现类需要实现一个枚举器方法:GetEnumerator,该方法返回IEnumerator类型的数据。

IDictionary和IList接口继承自ICollection作为更为专用的接口,其中IDictionary接口是键/值对接口,它的实现如HashTable类;

IList是值的集合,其成员可通过索引访问,如ArrayList类,次类集合与数组相比,可以认为是可变的集合,优点有,长度自动增长等。

IEnumerable和IEnumerable<T>是所有集合或集合接口的基接口,所有集合接口或集合都继承、实现了它。其中IEnumerable是最底层的接口。在非泛型集合里存放的都是System.Object类型。

如果某个类型实现了IEnumerable接口,就意味着它可以被迭代访问,也就可以称之为集合类型(可枚举)。

唯一方法是 GetEnumerator,此方法用于返回支持 IEnumerator 的对象。每次调用GetEnumerator()方法时都需要创建一个新的对象,同时迭代器必须保存自身的状态,记录此时已经迭代到哪一个元素

foreach内部使用迭代器的MoveNext和Current完成元素的遍历。

集合概述

1、ArrayList 
ArrayList与Array的名字很相似,现在来比较一下两者的异同。 
  相同点: 
  (1)、两者都实现了IList、ICollection、IEnumerable,ICloneable接口。 
  (2)、两者都可以使用整数索引访问集合中的元素,包括读取和赋值,且集合中的索引都从0开始。 
  不同点: 
  (1)、ArrayList是集合,而Array是数组。 
  (2)、ArrayList是具体类,Array是抽象类。 
    (3)、数组必须在实例化时指定元素的数量,该数量一旦确定就不可以更改了,而ArrayList扩展了这一点,当实例化一个ArrayList实例时可以不指定集合元素数(有默认初始容量),当然你也可以指定初始容量。 
  (4)、获取数组的元素数时使用Length属性,而获取ArrayList集合的元素数时使用Count属性。 
  (5)、数组可以有多维,而ArrayList只能是一维。
ArrayList类是一个特殊的数组。通过添加和删除元素,就可以动态改变数组的长度。ArrayList是命名空间System.Collections下的一部分,在使用该类时必须进行引用,同时继承了IList接口,提供了数据存储和检索。ArrayList对象的大小是按照其中存储的数据来动态扩充与收缩的。所以,在声明ArrayList对象时并不需要指定它的长度。 
一.优点 
1。支持自动改变大小的功能 
2。可以灵活的插入元素 
3。可以灵活的删除元素 
二.局限性 
跟一般的数组比起来,速度上差些

特定类型(不包括Object)的Array的性能比ArrayList好,这是因为ArrayList的元素属于Object类型,所以在存储或检索值类型时通常会发生装箱和拆箱

容量动态改变:存储容量小于将要存储元素之后总容量,容量一般成倍增长,4,8。

如果列表的容量改变,整个集合会分配到新的内存块,List<T> 泛型实现代码中,使用T类型数组,通过重新分配内存,创建新数组,Array.copy()将旧数组元素复制到新数组中。

使用TrimExcess()和Capacity可以重新设置容量

List<int> intList2 = new List<int>(){1,2,3};

List集合初始值设定项没有反映在IL代码中,而是每一项调用add

2、非泛型集合HashTable 

注意Hashtable,t是小写的。由于是非泛型集合,因此存储进去的都是object类型,不管是键还是值。 

简述

在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对,其中key通常可用来快速查找,同时key是区分大小写;value用于存储对应于key的值。Hashtable中keyvalue键值对均为object类型,所以Hashtable可以支持任何类型的keyvalue键值对.

  Hashtable的要点。 
  (1)、Hashtable仅有非泛型版本。 
  (2)、Hashtable类中的键不允许重复,但值可以。 
  (3)、Hashtable类所存储的键值对中,值可以为null,但键不允许为null。 
  (4)、Hashtable不允许排序操作。 

3、Queue和Queue<T> 
  Queue成为队列,队列是这样一种数据结构,数据有列表的一端插入,并由列表的另一端移除。就像单行道,只能从一段进,从一端出。
  Queue的一些重要特性。 
  1、先进先出 
  2、可以添加null值到集合中 
  3、允许集合中的元素重复 
  4、Queue容量会按需自动添加 
  5、Queue的等比因子是当需要更大容量时当前容量要乘以的数字,默认是2.0。

4、Stack和Stack<T> 
  Stack称为栈,栈和队列非常相似,只不过队列是先进先出,而栈中的数据添加和移除都在一端进行,遵守栈中的数据则后进先出。
  Stack类的一些重要特性如下: 
  1、后进先出。 
  2、可以添加null值到集合中。 
  3、允许集合中的元素重复。 
  4、Stack的容量会按需自动增加。 

5、SortedListSortedList<TKey, TValue>

1、SortedList定义

System.Collections.SortedList类表示键/值对的集合,这些键值对按键排序并可按照键和索引访问。SortedList 在内部维护两个数组以存储列表中的元素;即,一个数组用于键,另一个数组用于相关联的值。每个元素都是一个可作为 DictionaryEntry 对象进行访问的键/值对。键不能为null,但值可以。

2.优点

1、SortedList 允许通过相关联键或通过索引对值进行访问,可提供更大的灵活性。

2、可根据需要自动增大容量。

SortedList类与HashTable类似,也表示一个键/值对集合,可以通过键和索引对元素进行访问,但不同的是,也是该类的最大作用所在,就是支持基于键的排序。在SortedList中,键和值分别保存在一个数组中,当向Sorted添加一个元素时,SortedList类添加一个元素时,SortedList会首先对key进行排序,然后根据排序结果计算出要插入到集合中的位置索引,再分别将key和value插入到各自数组的指定索引位置。当使用foreach循环集合中的元素时,SortedList会将相同索引位置的key和value放进一个DictionaryEntry类型的对象,然后返回。 

.备注

1、SortedList 的容量是 SortedList 可以保存的元素数。SortedList 的默认初始容量为 0。随着元素添加到 SortedList 中,在需要时可以通过重新分配自动增加容量。可通过调用 TrimToSize方法 或通过显式设置 Capacity 属性减少容量。

2、SortedList 中不允许重复键。

3、SortedList的索引顺序基于排序顺序。当添加元素时,元素将按正确的排序顺序插入 SortedList,同时索引会相应地进行调整。当移除元素时,索引也会相应地进行调整。因此,当在 SortedList 中添加或移除元素时,特定键/值对的索引可能会更改。

4.当不向集合中添加新元素,则调用TrimToSize方法可用于最小化集合的内存开销。

5、通过设置 SortedList 中不存在的键值(例如,myCollection[“myNonexistentKey”] = myValue),还可以使用 Item 属性添加新元素。但是,如果指定的键已经存在于 SortedList 中,则设置 Item 属性将改写旧值。相比之下,Add 方法不修改现有元素。

6、键不能为 空引用(在 Visual Basic 中为 Nothing),但值可以。若要区分由于未找到指定键而返回的 空引用(在 Visual Basic 中为 Nothing) 和由于指定键的值为 空引用(在 Visual Basic 中为 Nothing) 而返回的 空引用(在 Visual Basic 中为 Nothing),请使用 Contains 方法或 ContainsKey 方法确定列表中是否存在该键。

6、BitArray 
  BitArray类实现了一个位结构,它是一个二进制位(0和1)的集合。BitArray的值表示true或false。true表示位打开,false表示位关闭。BitArray实现了ICollection和IEnumerable,ICloneable接口。 
  BitArray的一些特性如下: 
  1、BitArray集合不支持动态调整,因此没有Add和Remove方法。 
  2、若需要调整集合的大小,可通过设置属性Length的值来实现。 
  3、集合中的索引从0开始。 
  4、使用BitArray(int length)构造函数初始化BitArray集合后,其值均为false。 
  5、BitArray集合之间支持按位“或”、“异或”、“与运算”,参与这三类运算的BitArray集合长度必须相等。否则会抛出异常。

7、.Dictionary<TKey,TValue>

,字典是一组独特的键和值的集合,其中每字典需要更多的内存,因为每一个value都有对应的key

Dictionary<TKey,TValue>的查询数据所花费的时间是所有集合类里面最快的,因为其内部使用了散列函数加双数组来实现,所以其查询数据操作的时间复杂度可以认为是O(1)。Dictionary<TKey,TValue>的实现是一种典型的牺牲空间换取时间(双数组)的做法。

Dictionary<TKey,TValue>之所以能实现快速查找元素,其内部使用哈希表来存储元素对应的位置,我们可以通过哈希值快速地从哈希表中定位元素所在的位置索引,从而快速获取到key对应的Value值。物极必反,Dictionary<TKey,TValue>的缺点也很明显,就是里面的数据是无序排列的,所以按照一定顺序遍历查找数据效率是非常低的。

Lookup

Dictionary<Tkey,Tvalue>类支持每个键关联一个值,Lookup<Tkey,Tvalue>类似于Dictionary<Tkey,Tvalue>类,但把键关联到一个值集上,这个类在程序集system.core中实现,用system.Linq名称空间定义。,

Lookup<TKey, TElement>不能像一般字典那样创建,而是必须调用toLookup()方法,该方法返回Lookup<TKey, TElement>对象,toLookup()方法是一个扩展方法,可以用于实现IEnumerable<T>接口的所有类型。

有序字典SortedDictionary

SortedDictionary <TKey, TValue>是一个二叉搜索树,其中的元素根据键来排序,该键类型必须实现IComparable<Tkey>接口,还可以创建实现了IComparer< TKey >的比较器,将比较用作有序字典构造函数的一个参数。

使用一种平衡搜索二叉树—红黑树,作为存储结构。因为基于二分查找,所以添加、查找、删除元素的时间复杂度是O(log n)。

SortedDictionary<TKey, TValue> 基于字典

SortedList<TKey, TValue> 基于数组

具有特征:

SortedList<TKey, TValue>比SortedDictionary<TKey, TValue>使用内存少

SortedDictionary<TKey, TValue>删除和插入元素比较快

在用已排好序数据填充集合时,若不需要修改容量,SortedList<TKey, TValue>比较快。

如果想要快速查询的同时又能很好的支持排序的话,并且添加和删除元素也比较频繁,可以使用SortedDictionary<TKey,TValue>

List

List是一种强类型列表可以通过索引访问的对象的列表。它可以发现在System.Collections.Generic 命名空间。

泛型的List 类提供了不限制长度的集合类型,List内部实现使用数据结构是数组。我们都知道数组是长度固定的,那么List不限制长度必定需要维护这个数组。实际上List维护了一定长度的数组(默认为4),当插入元素的个数超过4或初始长度时,会去重新创建一个新的数组,这个新数组的长度是初始长度的2倍,然后将原来的数组赋值到新的数组中。

数组扩容的场景涉及到对象的创建和赋值,是比较消耗性能的。所以如果能指定一个合适的初始长度,能避免频繁的对象创建和赋值。再者,因为内部的数据结构是数组,插入和删除操作需要移动元素位置,所以不适合频繁的进行插入和删除操作;但是可以通过数组下标查找元素。所以List适合读多写少的场景。

LinkedList

链表是一个通用的双向链表在c#。List只允许顺序存取。LinkedList允许常量时间插入或者删除操作,但只有顺序存取的元素。

上面我们提到List适合读多写少的场景,那么必定有一个List适合写多读少的场景,就是这货了——LinkedList。至于为什么适合写多读少,熟悉数据结构的同学应该已经猜到了。因为LinkedList的内部实现使用的是链表结构,而且还是双向链表。

3.HashSet

HashSet是一个无序的能够保持唯一性的集合。我们可以将HashSet看作是简化的Dictionary<TKey,TValue>,只不过Dictionary<TKey,TValue>存储的键值对对象,而HashSet存储的是普通对象。其内部实现也和Dictionary<TKey,TValue>基本一致,也是散列函数加双数组实现的,区别是存储的Slot结构体不再有key。

HashSet非常适合在我们需要保持集合内元素唯一性但又不需要按顺序排列的时候。HashSet不支持下标访问。

4.SortedSet

SortedSetHashSet,就像SortedDictionary<TKey,TValue>Dictionary<TKey,TValue>一样。SortedSet支持元素按顺序排列,内部实现也是红黑树,并且SortedSet对于红黑树的操作方法和SortedDictionary<TKey,TValue>完全相同。所以不再做过多的分析。

5.Stack

栈是一种后进先出的结构 不支持按下标访问,C#的栈是借助数组实现的

6.Queue

队列是一种先进先出的结构, 不支持按下标访问。C#的队列也是借助数组实现的,有了前面的经验,借助数组实现必然会有数组扩容。C#的队列实现其实是循环队列的方式,可以简单的理解为将队列的头尾相接。至于为什么要这么做?为了节省存储空间和减少元素的移动。因为元素出队列时后面的元素跟着前移是非常消耗性能的,但是不跟着向前移动的话,前面就会一直存在空闲的空间浪费内存。所以使用循环队列来解决这种问题。

线程安全的集合类

需要我们注意的是,上面我们所介绍的集合并不是线程安全的,在多线程环境下,可能会出现线程安全问题。在多线程读的情况下,我们使用普通集合即可。在多线程添加/更新/删除时,我们可以采用手动锁定的方式确保线程安全,但是应该注意加锁的范围和粒度,加锁不当可能会导致程序性能低下甚至产生死锁。

更好的选择的是使用的C#提供的线程安全集合(命名空间:System.Collections.Concurrent)。线程安全集合使用几种算法来最小化线程阻塞。

  1. ConcurrentQueue: 线程安全版本的Queue
  2. ConcurrentStack:线程安全版本的Stack
  3. ConcurrentBag:线程安全的对象集合
  4. ConcurrentDictionary:线程安全的Dictionary

包含不重复的元素称为集(set),.net framek包含两个集(HashSer<T>和SortedSet<T>).都实现ISet<T>接口,HashSet<T>包含不重复元素的无序列表,SortedSet<T>包含不重复元素有序列表。

ISet<T>接口的方法可以提供创建合集,交集,给出一个集是另外一个集的子集或者超集信息。

HashSet<T>实现ICollection接口,还提供add()方法,返回布尔值,是否添加元素,如果已存在,不添加。

除了用CreateMask()创建掩码,可以自己定义掩玛

可观察的集合

需要集合元素何时添加和删除信息,就需要用到ObservableCollection<T>类,这个类为WPF定义,这样UI就可以得知集合变化。

在程序集Window.Base定义,用户需要引用程序集,这个类名称空间为System.Collections.ObjectModel;

数组(Array)的不足(即:集合与数组的区别)

1. 数组是固定大小的,不能伸缩。虽然System.Array.Resize这个泛型方法可以重置数组大小,但是该方法是重新创建新设置大小的数组,用的是旧数组的元素初始化。随后以前的数组就废弃!而集合却是可变长的。

2. 数组要声明元素的类型,集合类的元素类型却是object。

3. 数组可读可写不能声明只读数组。集合类可以提供ReadOnly方法以只读方式使用集合。

4. 数组要有整数下标才能访问特定的元素,然而很多时候这样的下标并不是很有用。集合也是数据列表却不使用下标访问。很多时候集合有定制的下标类型,对于队列和栈根本就不支持下标访问!

字典(Directonary)

Hashtable和Dictionary<K, V>类型
 1:单线程中推荐使用Dictionary,有泛型优势,且读取速度较快,容量利用更充分.
 2:多线程中推荐使用Hashtable,默认Hashtable允许单线程写入, 多线程读取对Hashtable进一步调用Synchronized()方法可以获得完全线程安全的类型,而Dictionary非线程安全,必须人为使用lock语句进行保护, 效率大减。
 3:Dictionary有按插入顺序排列数据的特性(注:但当调用Remove()删除过节点后顺序被打乱), 因此在需要体现顺序的情境中使用Dictionary能获得一定方便。

HashTable应用场合:做对象缓存,树递归算法的替代,和各种需提升效率的场合。HashTable中的key/value均为object类型,由包含集合元素的存储桶组成。存储桶是 HashTable中各元素的虚拟子组,与大多数集合中进行的搜索和检索相比,存储桶可令搜索和检索更为便捷。每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生成的并基于该元素的键。HashTable的优点就在于其索引的方式,速度非常快。如果以任意类型键值访问其中元素会快于其他集合,特别是当数据量特别大的时候,效率差别尤其大。

排序列表(SortedList)

与哈希表类似,区别在于SortedList中的Key数组排好序的

名-值集合(NameValueCollection)

NameValueCollection与HashTable很类似,但是他们还是有区别的,HashTable 的KEY是唯一性,而NameValueCollection则不唯一

接口

非泛型集合接口 泛型集合接口说明
ICollectionICollection<T>定义所有集合的大小(Count),枚举器(foreach)和同步(copyto)方法,继承自IEnumerable
IListIList<T>表示可按照索引单独访问的一组对象(像数组一样)
IDictionary    IDictionary<T>   表示键/值对的集合
IComparer IComparer<T>定义类型为比较两个对象而实现的方法
IEqualityComparer  IEqualityComparer<T>  定义方法以支持对象的相等比较
IEnumerableIEnumerable<T>公开枚举器。实现了该接口意味着允许foreach语句循环访问集合中的元素
IEnumerator IEnumerator<T>支持在泛型集合上进行简单迭代

MSDN来说IEnumerable的方法,无扩展方法

1、IEnumerable和IEnumerable<T> 

方法说明
GetEnumerator返回一个循环访问集合的枚举器。 实现或继承了该接口,就是为了这个方法,可以foreach遍历

2、ICollection接口

继承了 IEnumerable

方法说明
CopyTo从特定的 Array 索引处开始,将 ICollection 的元素复制到一个 Array 中。
GetEnumerator返回一个循环访问集合的枚举数。 (继承自 IEnumerable。)
属性 
IsSynchronized获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。
SyncRoot获取可用于同步 ICollection 访问的对象。
Count 获取 ICollection 中包含的元素数。 原来Count的源头在这里。

3、ICollection<T>

继承了 IEnumerable和IEnumerable<T>

方法说明
Add将某项添加到 ICollection<T> 中。
Clear从 ICollection<T> 中移除所有项。
Contains 确定 ICollection<T> 是否包含特定值。
Remove从 ICollection<T> 中移除特定对象的第一个匹配项。
CopyTo从特定的 Array 索引开始,将 ICollection<T> 的元素复制到一个 Array 中。
GetEnumerator返回一个循环访问集合的枚举数。 (继承自 IEnumerable。)
属性 
IsReadOnly获取一个值,该值指示 ICollection<T> 是否为只读。
Count获取 ICollection<T> 中包含的元素数。
 可以添加元素和移除元素,记录元素个数,是否包含,有集合样子

4、IList 

IList继承了ICollection和IEnumerable

方法说明
IndexOf确定 IList 中特定项的索引。
Insert将一个项插入指定索引处的 IList。
RemoveAt移除指定索引处的 IList 项。
Add将某项添加到 IList 中。
Clear从 IList 中移除所有项。
Contains确定 IList 是否包含特定值。
Remove从 IList 中移除特定对象的第一个匹配项。
CopyTo从特定的 Array 索引开始,将 ICollection<T> 的元素复制到一个 Array 中。(继承自 ICollection。)
GetEnumerator返回一个循环访问集合的枚举器。 (继承自 IEnumerable。)
属性 
IsFixedSize获取一个值,该值指示 IList 是否具有固定大小。
Item(this)获取或设置指定索引处的元素。
IsReadOnly获取一个值,该值指示 ICollection<T> 是否为只读。
IsSynchronized获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。(继承自 ICollection。)
SyncRoot获取可用于同步 ICollection 访问的对象。(继承自 ICollection。)
Count 获取 ICollection 中包含的元素数。 原来Count的源头在这里。(继承自 ICollection。)
 支持索引获取和设置就是IList这个源头的,可以通过索引插入,移除索引处元素,(扩展索引操作)

5、IList<T> 
IList<T>继承了ICollection<T>,IEnumerable<T>,IEnumerable

方法说明
IndexOf确定 IList<(Of <(T>)>) 中特定项的索引。
Insert将一个项插入指定索引处的 IList<(Of <(T>)>)。
RemoveAt移除指定索引处的 IList<(Of <(T>)>) 项。
Add将某项添加到 ICollection<(Of <(T>)>) 中。 (继承自 ICollection<(Of <(T>)>)。)
Clear从 ICollection<(Of <(T>)>) 中移除所有项。 (继承自 ICollection<(Of <(T>)>)。)
Contains确定 ICollection<(Of <(T>)>) 是否包含特定值。 (继承自 ICollection<(Of <(T>)>)。)
Remove从 ICollection<(Of <(T>)>) 中移除特定对象的第一个匹配项。 (继承自 ICollection<(Of <(T>)>)。)
CopyTo从特定的 Array 索引开始,将 ICollection<(Of <(T>)>) 的元素复制到一个 Array 中。 (继承自 ICollection<(Of <(T>)>)。)
GetEnumerator返回一个循环访问集合的枚举数。 (继承自 IEnumerable。)
属性 
Item(this)获取或设置指定索引处的元素。
IsReadOnly获取一个值,该值指示 ICollection<(Of <(T>)>) 是否为只读。 (继承自 ICollection<(Of <(T>)>))
Count获取 ICollection<(Of <(T>)>) 中包含的元素数。 (继承自 ICollection<(Of <(T>)>)。)
 支持索引获取和设置就是IList这个源头的。可以通过索引插入,移除索引处元素(扩展索引操作)

6、IDictionary<TKey,TValue>接口 

IDictionary<TKey,TValue>继承了ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable,是最底层出现的键/值对集合了

方法说明
ContainsKey确定 IDictionary<(Of <(TKey, TValue>)>) 是否包含具有指定键的元素。
TryGetValue获取与指定的键相关联的值。
Add已重载。添加一个带有所提供的键和值的元素。
Clear从 ICollection<(Of <(T>)>) 中移除所有项。 (继承自 ICollection<(Of <(T>)>)。)
Contains确定 ICollection<(Of <(T>)>) 是否包含特定值。 (继承自 ICollection<(Of <(T>)>)。)
Remove已重载。移除带有指定键的元素。
CopyTo从特定的 Array 索引开始,将 ICollection<(Of <(T>)>) 的元素复制到一个 Array 中。 (继承自 ICollection<(Of <(T>)>)。)
GetEnumerator返回一个循环访问集合的枚举器。 (继承自 IEnumerable。)
属性 
Keys获取包含 IDictionary<(Of <(TKey, TValue>)>) 的键
Values获取包含 IDictionary<(Of <(TKey, TValue>)>) 中的值
Item(this)获取或设置指定索引处的元素。
IsReadOnly获取一个值,该值指示 ICollection<(Of <(T>)>) 是否为只读。 (继承自 ICollection<(Of <(T>)>))
Count获取 ICollection<(Of <(T>)>) 中包含的元素数。 (继承自 ICollection<(Of <(T>)>)。)
 

通过键获取值,插入新的键值对,是否包含KEY,通过KEY移除键值对元素(扩展了通过操作键值对)

7、IDictionary

     继承了ICollection, IEnumerable

方法说明
Add在 IDictionary 对象中添加一个带有所提供的键和值的元素。
Clear从 IDictionary 对象中移除所有元素。
Contains确定 IDictionary 对象是否包含具有指定键的元素。
Remove移除带有指定键的元素。
CopyTo从特定的 Array 索引开始,将 ICollection<(Of <(T>)>) 的元素复制到一个 Array 中。 (继承自 ICollection<(Of <(T>)>)。)
GetEnumerator重载,返回IDictionaryEnumerator,返回一个循环访问集合的枚举器。 (继承自 IEnumerable。)
属性 
Keys获取 ICollection 对象,它包含 IDictionary 对象的键。
Values获取 ICollection 对象,它包含 IDictionary 对象中的值。
IsFixedSize获取一个值,该值指示 IDictionary 对象是否具有固定大小。
Item(this)获取或设置具有指定键的元素。
IsReadOnly获取一个值,该值指示 IDictionary 对象是否为只读。
IsSynchronized获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。(继承自 ICollection。)
SyncRoot获取可用于同步 ICollection 访问的对象。(继承自 ICollection。)
Count 获取 ICollection 中包含的元素数。 原来Count的源头在这里。(继承自 ICollection。)
 

通过键获取值,插入新的键值对,是否包含KEY,通过KEY移除键值对元素(扩展了通过操作键值对)

8、ISet<T> 
ISet<T>同样是继承自ICollection<T>,IEnumerable<T>,IEnumerable

方法说明
ExceptWith从当前集内移除指定集合中的所有元素。
IntersectWith修改当前集,使该集仅包含指定集合中也存在的元素。
IsProperSubsetOf确定当前的设置是否正确 (严格) 指定集合的子集。
IsProperSupersetOf确定当前的设置是否正确 (严格) 指定集合中的超集。
IsSubsetOf确定一个集是否为指定集合的子集。
IsSupersetOf确定当前集是否为指定集合的超集。
Overlaps确定当前集是否与指定的集合重叠。
SetEquals确定当前集与指定的集合中是否包含相同的元素。
SymmetricExceptWith修改当前集,使该集仅包含当前集或指定集合中存在的元素(但不可包含两者共有的元素)。
UnionWith修改当前设置,以使其包含当前集或指定的集合中的所有元素。
Add已重载,向当前集内添加元素,并返回一个指示是否已成功添加元素的值。
Clear从 ICollection<(Of <(T>)>) 中移除所有项。 (继承自 ICollection<(Of <(T>)>)。)
Contains确定 ICollection<(Of <(T>)>) 是否包含特定值。 (继承自 ICollection<(Of <(T>)>)。)
Remove从 ICollection<(Of <(T>)>) 中移除特定对象的第一个匹配项。 (继承自 ICollection<(Of <(T>)>)。)
CopyTo从特定的 Array 索引开始,将 ICollection<(Of <(T>)>) 的元素复制到一个 Array 中。 (继承自 ICollection<(Of <(T>)>)。)
GetEnumerator返回一个循环访问集合的枚举数。 (继承自 IEnumerable。)
属性 
IsReadOnly获取一个值,该值指示 ICollection<(Of <(T>)>) 是否为只读。 (继承自 ICollection<(Of <(T>)>))
Count获取 ICollection<(Of <(T>)>) 中包含的元素数。 (继承自 ICollection<(Of <(T>)>)。)

IComparer接口,这个接口就一个方法,用于如何比较两个对象

public class StringLengthComparer : IComparer<string>
    {
        public int Compare(string s1, string s2)
        {
            if (s1.Length > s2.Length)
            {
                return (1);
            }
            else if (s1.Length < s2.Length)
            {
                return (2);
            }
            else
            {
                return (0);
            }
        }
    }

集合用法

ArrayList用法

ArrayList实现了IList、ICollection、IEnumerable,ICloneable接口。 

方法说明
Adapter(静态)为特定的 IList 创建 ArrayList 包装。
AddRange将 ICollection 的元素添加到 ArrayList 的末尾。
BinarySearch已重载。 使用对分检索算法在已排序的 ArrayList 或它的一部分中查找特定元素。
Clone创建 ArrayList 的浅表副本。
FixedSize(静态)已重载。 返回具有固定大小的列表包装,其中的元素允许修改,但不允许添加或移除。
GetRange返回 ArrayList,它表示源 ArrayList 中元素的子集。
InsertRange将集合中的某个元素插入 ArrayList 的指定索引处。
LastIndexOf已重载。 返回 ArrayList 或它的一部分中某个值的最后一个匹配项的从零开始的索引。
ReadOnly已重载。 返回只读的列表包装。
RemoveRange从 ArrayList 中移除一定范围的元素。
Repeat返回 ArrayList,它的元素是指定值的副本。(具有 count 所指定的元素数)
Reverse已重载。 将 ArrayList 或它的一部分中元素的顺序反转。
SetRange将集合中的元素复制到 ArrayList 中一定范围的元素上。
Sort已重载。 对 ArrayList 或它的一部分中的元素进行排序。
Synchronized已重载。 返回同步的(线程安全)列表包装。
ToArray已重载。 将 ArrayList 的元素复制到新数组中。
TrimToSize将容量设置为 ArrayList 中元素的实际数目。
IndexOf已重载。 返回 ArrayList 或它的一部分中某个值的第一个匹配项的从零开始的索引。
Insert将一个项插入指定索引处的 ArrayList 。
RemoveAt移除指定索引处的 ArrayList 项。
Add将对象添加到 ArrayList 的结尾处。
Clear从 IList 中移除所有项。
Contains确定 IList 是否包含特定值。
Remove从 IList 中移除特定对象的第一个匹配项。
CopyTo从特定的 Array 索引开始,将 ICollection<T> 的元素复制到一个 Array 中。(继承自 ICollection。)
GetEnumerator返回一个循环访问集合的枚举器。 (继承自 IEnumerable。)
属性 
Capacity获取或设置 ArrayList 可包含的元素数。
IsFixedSize获取一个值,该值指示 IList 是否具有固定大小。
Item(this)获取或设置指定索引处的元素。
IsReadOnly获取一个值,该值指示 ICollection<T> 是否为只读。
IsSynchronized获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。(继承自 ICollection。)
SyncRoot获取可用于同步 ICollection 访问的对象。(继承自 ICollection。)
Count 获取 ICollection 中包含的元素数。 原来Count的源头在这里。(继承自 ICollection。)
 static void Main(string[] args)
        {

            ArrayList arrayList = new ArrayList();
            arrayList.Add(1);                       //Add方法,将一个元素添加到ArrayList中
            arrayList.Add("你好");
            arrayList.Add(3.265);
            IList iList = arrayList;
            ICollection iCollection = iList;
            IEnumerable iEnumerable = iCollection;  //体现了ArrayList的继承关系
            foreach (object obj in iEnumerable)
            {
                Console.WriteLine(obj.ToString());
            }

            bool b = arrayList.Contains("你好");  //确定ArrayList中是否包含某元素
            Console.WriteLine(b);                 //输出 True
            object[] objArr = new object[arrayList.Count + 1];
            objArr[0] = "我是用来占位的";
            arrayList.CopyTo(objArr, 1); //便宜一位,也就是接受数组从1开始,默认是0
            foreach (object obj in objArr)
            {
                Console.Write(obj.ToString() + "-");    //输出 我是用来占位的-1-你好-3.265-
            }
            ArrayList AL = ArrayList.FixedSize(arrayList);  //静态方法 返回一个固定大小的ArrayList对象,数量不许改变。也就是说不能添加和删除。
            Console.WriteLine(AL.IsFixedSize);  //输出True
            //AL.Add(111); 此处报异常,"集合的大小是固定的"
            ArrayList ALReadOnly = ArrayList.ReadOnly(arrayList);
            Console.WriteLine(ALReadOnly.IsReadOnly);   //输出True
            ArrayList AL1 = arrayList.GetRange(1, 2);   //按照索引顺序截取出子集
            foreach (object obj in AL1)
            {
                Console.Write(obj.ToString());  //输出 你好3.265    可以截取出的新ArrayList只包含1,2位
            }
            Console.WriteLine();

            int indexLocation = arrayList.IndexOf(1);   //从左边开始检索,返回第一个匹配到的元素的顺序
            Console.WriteLine(indexLocation);   //输出  0

            arrayList.Add(1);       //为了体现LastIndexOf的不同,先添加一个1
            int lastLocation = arrayList.LastIndexOf(1);
            Console.WriteLine(lastLocation);    //返回3

            arrayList.Insert(2, "Insert插入的元素");  //这个方法与Add的不同在于它可以在任意位置插入
            foreach (object obj in arrayList)
            {
                Console.Write(obj.ToString() + " ");    //输出 1 你好 Insert插入的元素 3.265 1
            }

            ArrayList arr = new ArrayList();
            arr.Add(1);
            arr.Add(2);
            arrayList.AddRange(arr);
            foreach (object obj in arrayList)
            {
                Console.Write(obj.ToString() + "-");    //输出 1 你好 Insert插入的元素 3.265 1 1 2可以看到将一个新的集合追加到了最后
            }
            arrayList.Remove(2);
            foreach (object obj in arrayList)
            {
                Console.Write(obj.ToString() + "-");    //输出 1 你好 Insert插入的元素 3.265 1 1 可以看到2已经被移除了
            }
            arrayList.RemoveAt(0);
            foreach (object obj in arrayList)
            {
                Console.Write(obj.ToString() + "-");    //输出 你好 Insert插入的元素 3.265 1 1 可以看到第0个元素"2"已经被移除了
            }
            Console.WriteLine();

            //arrayList.Reverse();
            //foreach (object obj in arrayList)
            //{
            //    Console.Write(obj.ToString() + "-");        //输出顺序倒转的所有元素
            //}

            ArrayList AL3 = new ArrayList();
            arrayList.SetRange(0,AL3);      //从第0位开始,将元素复制到AL3中
            foreach (object obj in AL3)
            {
                Console.Write(obj.ToString() + "-");    //输出 你好 Insert插入的元素 3.265 1 1
            }

            object[] objArrs = new object[arrayList.Count];
            objArrs = arrayList.ToArray();
            foreach (object obj in objArrs)
            {
                Console.Write(obj.ToString() + "-");
            }

            Console.WriteLine();

            arrayList.Capacity = 5;     //读取或设置可包含元素的数量,如果小于当前会报错。
            Console.WriteLine(arrayList.Count);     //输出5   
            arrayList.TrimToSize();
            Console.WriteLine(arrayList.Count);     //输出5  
            aList.RemoveRange(1,3);//从ArrayList中移除一定范围的元素。Index表示索引,count表示从索引处开始的数目 
            aList.Sort();//排序 
aList.Reverse();//反转 
            Console.ReadKey();
        }

二,哈希表的简单操作

 Hashtable实现了IDictionary、ICollection以及IEnumerable,ISerializable, IDeserializationCallback, ICloneable接口。

在哈希表中添加一个keyvalue键值对:HashtableObject.Add(key,value); 
在哈希表中去除某个keyvalue键值对:HashtableObject.Remove(key); 
从哈希表中移除所有元素: HashtableObject.Clear(); 
判断哈希表是否包含特定键key: HashtableObject.Contains(key); 

2、非泛型集合HashTable 用法

 static void Main(string[] args)
        {
            Hashtable ht = new Hashtable();
            ht.Add(1,1);
            ht.Add("我爱你","是吗?");
            Console.WriteLine(ht.Count);    //输出 2
            Console.WriteLine(ht["我爱你"]);   //输出 "是吗?"  用键 获取值
            Console.WriteLine(ht.Contains(1));  //输出True
 //遍历
 for(KeyValuePair de in ht) //ht为一个Hashtable实例
 {
   Console.WriteLine(de.Key);//de.Key对应于keyvalue键值对key
   Console.WriteLine(de.Value);//de.Key对应于keyvalue键值对value
 }
        }

3、Queue和Queue<T> 用法

Queue类实现了ICollection和IEnumerable, ICloneable接口。 QueueQueue<T> 类实现了 ICollection, IEnumerable,IEnumerable<T>。 

成员类型说明
Clear方法从Queue中移除所有对象,清空队列。
Contains方法确定某元素是否在Queue中
Enqueue方法将对象添加到Queue的结尾处入列
Dequeue方法移除并返回位于Queue开始处的对象(出列)
Peek方法返回位于Queue开始出的对象,但不将其移除,与出列不同,出列是会移除的

实现

static void Main(string[] args)
        {
            Queue q = new Queue();
            q.Enqueue(1);
            q.Enqueue("想家了!");
            q.Enqueue(1.23);
            Console.WriteLine(q.Peek());    //输出1 获取值但不移除,与出列不同
            int Count = q.Count;            //出队的时候q.Count在变化,因此q.Count放在循环条件里是不妥的
            for (int i = 0; i < Count; i++)
            {
                Console.WriteLine(q.Dequeue().ToString());  //注意 输出 1 想家了 1.23  都是从最先添加的先拿
            }
            Console.WriteLine(q.Count); //输出0 出列一次,就自动移除了。

            Queue<int> qInt = new Queue<int>();
            qInt.Enqueue(1);
            qInt.Enqueue(2);
            qInt.Enqueue(3);
            Console.WriteLine(qInt.Peek());     //输出1
            int IntCount = qInt.Count;
            for (int i = 0; i < IntCount; i++)
            {
                Console.WriteLine(qInt.Dequeue());  //注意 输出 123  都是从最先添加的先拿
            }
            Console.WriteLine(q.Count); //输出0 出列一次,就自动移除了。

            Console.ReadKey();
        }

4、Stack和Stack<T> 用法

Stack类实现了ICollection和IEnumerable, ICloneable接口。 Stack<T>实现了 ICollection, IEnumerable,IEnumerable<T>

成员类型说明
Clear方法从Stack中移除所有对象
Contains方法确定某元素是否在Stack中
Push方法将对象插入Stack的顶部入栈
Pop方法移除并返回Stack顶部的对象 出栈
Peek方法返回位于Stack顶部的对象,但不移除,注意出栈是移除的。它不移除仅仅返回。
Count属性获取Stack中包含的元素
static void Main(string[] args)
        {
            Stack s = new Stack();
            s.Push(1);
            s.Push("想回家了!");
            s.Push(1.23);
            Console.WriteLine(s.Peek());    //输出1.23

            int Count = s.Count;    //在for里面如果是s.Count的话,很容易乱,因为出栈操作s.Count是在变动着的。
            for (int i = 0; i < Count; i++)
            {
                Console.WriteLine(s.Pop());     //输出 1.23 想回家了 1
            }
            Console.WriteLine(s.Count);     //输出0


            Stack<int> sInt = new Stack<int>();
            sInt.Push(1);
            sInt.Push(2);
            sInt.Push(3);
            Console.WriteLine(sInt.Peek());    //输出3

            int IntCount = sInt.Count;    //差点犯了逻辑错误,在for里面如果是s.Count的话,很容易乱,因为出栈操作s.Count是在变动着的。
            for (int i = 0; i < IntCount; i++)
            {
                Console.WriteLine(sInt.Pop());     //输出 3 2 1
            }
            Console.WriteLine(sInt.Count);     //输出0


            Console.ReadKey();
        }

5、SortedListSortedList<TKey, TValue>用法

 SortedList类实现了IDictionary、ICollection以及IEnumerable,ICloneable接口。

 SortedList<TKey, TValue>类实现了IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable接口。

SortedList的构造器

列出有特点方法

成员说明
Bool ContainsKey(object key)确定 SortedList 是否包含特定键。
Bool ContainsValue(object value)确定 SortedList 是否包含特定值。
Object GetKey(int index)获取 SortedList 的指定索引处的键。
Object GetByIndex(int index)获取 SortedList 的指定索引处的值。
IList GetKeyList()获取 SortedList 中的键。
IList GetValueList()获取 SortedList 中的值。
Int IndexOfKey(object key)返回 SortedList 中指定键的从零开始的索引。
Int IndexOfValue(object value)返回指定的值在 SortedList 中第一个匹配项的从零开始的索引。
Void SetByIndex(int index,object value)替换 SortedList 中指定索引处的值。
Void TrimToSize()将容量设置为 SortedList 中元素的实际数目。
属性 
Capacity获取或设置 ArrayList 可包含的元素数。
static void Main(string[] args)
        {
            SortedList SL = new SortedList();
            SL.Add("txt","txt");                    //Add的时候会自动排序
            SL.Add("jpg","jpg");
            SL.Add("png","png");
            foreach (DictionaryEntry de in SL)      //返回的是DictionaryEntry对象
            {
                Console.Write(de.Key + ":" + de.Value + "  ");  //输出 jpg:jpg png:png txt:txt    //注意这个顺序啊,添加的时候就自动排序了
            }

            Console.WriteLine();
            SortedList<int,string> SLString = new SortedList<int,string>();
            SLString.Add(3, "333");
            SLString.Add(2, "222");
            SLString.Add(1, "111");
            foreach (KeyValuePair<int,string> des in SLString)  //返回的是KeyValuePair,在学习的时候尽量少用var,起码要知道返回的是什么
            {
                Console.Write(des.Key + ":" + des.Value + " ");
            }

            Console.ReadKey();
        }

6、BitArray 用法

BitArray实现了ICollection和IEnumerable,ICloneable接口。 

方法说明
And对当前 BitArray 中的元素和指定的 BitArray 中的相应元素执行按位 AND 运算。
Or对当前 BitArray 中的元素和指定的 BitArray 中的相应元素执行按位“或”运算。
Xor对当前 BitArray 中的元素和指定的 BitArray 中的相应元素执行按位“异或”运算。
Not反转当前 BitArray 中的所有位值,以便将设置为 true 的元素更改为 false;将设置为 false 的元素更改为 true。
Get获取 BitArray 中特定位置处的位的值。
Set将 BitArray 中特定位置处的位设置为指定值。
SetAll将 BitArray 中的所有位设置为指定值。
Clone创建 BitArray 的浅表副本。
CopyTo从特定的 Array 索引处开始,将 ICollection 的元素复制到一个 Array 中。
GetEnumerator返回一个循环访问集合的枚举数。 (继承自 IEnumerable。)
属性 
Length获取或设置 BitArray 中元素的数目。
Item获取或设置 BitArray 中特定位置的位的值。
IsReadOnly获取一个值,该值指示 BitArray 是否为只读。
IsSynchronized获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。
SyncRoot获取可用于同步 ICollection 访问的对象。
Count 获取 ICollection 中包含的元素数。 原来Count的源头在这里。
static void Main(string[] args)
        {
            BitArray BA = new BitArray(3);
            BA[0] = true;
            BA[1] = false;
            BA[2] = true;

            BitArray BB = new BitArray(3);
            BA[0] = true;
            BA[1] = false;
            BA[2] = true;

            BitArray BOr = BA.Or(BB); //与运算,返回一个新的BitArray
            foreach (var b in BOr)
            {
                Console.Write(b + "-");     //True-False-True
            }

            Console.ReadKey();
        }

7、Dictionary<TKey, TValue>字典

继承了IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, ISerializable, IDeserializationCallback

方法说明
Equals(Object)确定指定的 Object 是否等于当前的 Object。 (继承自 Object。)
Finalize允许对象在“垃圾回收”回收之前尝试释放资源并执行其他清理操作。 (继承自 Object。)
GetHashCode用作特定类型的哈希函数。 (继承自 Object。)
GetType获取当前实例的 Type。 (继承自 Object。)
MemberwiseClone创建当前 Object 的浅表副本。 (继承自 Object。)
ToString返回表示当前对象的字符串。 (继承自 Object。)
GetObjectData实现 System.Runtime.Serialization.ISerializable 接口,并返回序列化 Dictionary 实例所需的数据。
OnDeserialization实现 System.Runtime.Serialization.ISerializable 接口,并在完成反序列化之后引发反序列化事件。
ContainsValue确定 Dictionary<TKey, TValue> 是否包含特定值。
ContainsKey确定 IDictionary<(Of <(TKey, TValue>)>) 是否包含具有指定键的元素。
TryGetValue获取与指定的键相关联的值。
Add已重载。添加一个带有所提供的键和值的元素。
Clear从 Dictionary<TKey, TValue> 中移除所有的键和值。
Contains确定 ICollection<(Of <(T>)>) 是否包含特定值。 (继承自 ICollection<(Of <(T>)>)。)
Remove已重载。移除带有指定键的元素。
CopyTo从特定的 Array 索引开始,将 ICollection<(Of <(T>)>) 的元素复制到一个 Array 中。 (继承自 ICollection<(Of <(T>)>)。)
GetEnumerator返回一个循环访问集合的枚举器。 (继承自 IEnumerable。)
属性 
Comparer获取用于确定字典中的键是否相等的 IEqualityComparer<T>
Keys获取包含 IDictionary<(Of <(TKey, TValue>)>) 的键
Values获取包含 IDictionary<(Of <(TKey, TValue>)>) 中的值
Item(this)获取或设置指定索引处的元素。
IsReadOnly获取一个值,该值指示 ICollection<(Of <(T>)>) 是否为只读。 (继承自 ICollection<(Of <(T>)>))
Count获取 ICollection<(Of <(T>)>) 中包含的元素数。 (继承自 ICollection<(Of <(T>)>)。)
  
  //定义
    Dictionary<string, string> openWith = new Dictionary<string, string>();

    //添加元素
    openWith.Add("txt", "notepad.exe");
    openWith.Add("bmp", "paint.exe");
    openWith.Add("dib", "paint.exe");
    openWith.Add("rtf", "wordpad.exe");

    //取值
    Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);

     //更改值
    openWith["rtf"] = "winword.exe";
    Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);

    //遍历key
    foreach (string key in openWith.Keys)
    {
        Console.WriteLine("Key = {0}", key);
    }

    //遍历value
    foreach (string value in openWith.Values)
    {
        Console.WriteLine("value = {0}", value);
    }

    //遍历value, Second Method
    Dictionary<string, string>.ValueCollection valueColl = openWith.Values;
    foreach (string s in valueColl)
    {
        Console.WriteLine("Second Method, Value = {0}", s);
    }

//遍历字典
    foreach (KeyValuePair<string, string> kvp in openWith)
    {
        Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
    }

    //添加存在的元素
    try
    {
        openWith.Add("txt", "winword.exe");
    }
    catch (ArgumentException)
    {
        Console.WriteLine("An element with Key = \"txt\" already exists.");
    }

    //删除元素
    openWith.Remove("doc");
    if (!openWith.ContainsKey("doc"))
    {
        Console.WriteLine("Key \"doc\" is not found.");
    }

    //判断键存在
    if (openWith.ContainsKey("bmp")) // True 
    {
        Console.WriteLine("An element with Key = \"bmp\" exists.");
    }

    //参数为其它类型 
    Dictionary<int, string[]> OtherType = new Dictionary<int, string[]>();
    OtherType.Add(1, "1,11,111".Split(','));
    OtherType.Add(2, "2,22,222".Split(','));
    Console.WriteLine(OtherType[1][2]);



    //参数为自定义类型
    //首先定义类
    class DouCube
    {
        public int Code { get { return _Code; } set { _Code = value; } } private int _Code;
        public string Page { get { return _Page; } set { _Page = value; } } private string _Page;
    } 

   //声明并添加元素
    Dictionary<int, DouCube> MyType = new Dictionary<int, DouCube>();
    for (int i = 1; i <= 9; i++)
    {
        DouCube element = new DouCube();
        element.Code = i * 100;
        element.Page = "http://www.doucube.com/" + i.ToString() + ".html";
        MyType.Add(i, element);
    }

    //遍历元素
    foreach (KeyValuePair<int, DouCube> kvp in MyType)
    {
        Console.WriteLine("Index {0} Code:{1} Page:{2}", kvp.Key, kvp.Value.Code, kvp.Value.Page);
    } 

List<T>用法

List<T>还提供了ForEach方法,参数用Action<T>( 返回类型void委托)声明,实现代码:

List<T>还提供了ForEach方法,参数用Action<T>声明;

实现代码:

   List<int> a = new List<int>();

   a.ForEach(i=>Console.Write(i));

用不同的方式在集合中搜索元素,可以获取查找元素索引,或者元素本身。

可以使用的办法有IndexOf(),LastIndexOf(),FindIndex(),FindLastIndex(),Find(),FindAll(),如果只检查元素是否存在,使用Exist()方法。

Findindex() 返回查找元素索引

Find(),返回查找元素

FindAll() 类似,但是找到第一项以后,不会停止迭代,而是继续迭代每一项,返回Predicate<T>为true的所有项。

可以使用List<T>的ConvertAll<TOutput> (),把所有类型的集合转换为另一种类型,使用一种Convert委托,定义如下:

public delegate TOutput Converter<in TInput, out TOutput>(TInput input);

TInput是委托方法参数,TOutput是返回类型参数。

排序

Sort()使用快速排序算法,比较所有元素,直到所有元素排好序。

Sort()使用好几个重载方法,泛型委托comparison, 泛型接口comparer,范围值参数和comparer

public void Sort();

public void Sort(Comparison<T> comparison);

public void Sort(IComparer<T> comparer);

public void Sort(int index, int count, IComparer<T> comparer);

集合中的元素只有实现类Icomparer接口,才能使用不带参数sort()

    racers2.Sort(new RacerComparer(CompareType.Country));

排序的另一种方式,使用重载的sort()方法,该方法需要一个Comparsion<T>委托。

public void Sort(Comparison<T> comparison);

Lookup<TKey, TElement>实现

      var racers = new List<Racer>();

      racers.Add(new Racer(26, "Jacques", "Villeneuve", "Canada", 11));

      var lookupRacers = racers.ToLookup(r => r.Country);

LinkedList示例

 LinkedList<int> nums = new LinkedList<int>();
        nums.AddLast(23);
        nums.AddFirst(9);
        LinkedListNode<int> node = nums.Find(6);
        nums.AddBefore(node, 5);
        foreach(int num in nums)
        {
            Console.WriteLine(num);
        }

Dictionary<TKey,TValue>实质 

mark

Dictionary<TKey,TValue>添加新元素的实现:

mark

mark

Dictionary<TKey,TValue>内部有两个数组,一个数组名为buckets,用于存放由多个同义词组成的静态链表头指针(链表的第一个元素在数组中的索引号,当它的值为-1时表示此哈希地址不存在元素);另一个数组为entries,它用于存放哈希表中的实际数据,同时这些数据通过next指针构成多个单链表。entries数组中所存放的是Entry结构体,Entry结构体由4个部分组成,如下所示:

mark

Dictionary<TKey,TValue>计算key的哈希值使用的是取余法,这种方式可能会产生冲突,所以需要进行冲突解决。Dictionary<TKey,TValue>解决冲突的方式是链接法。

mark

我们可以根据源码来模拟推导一下这个过程:

当添加第一个元素时,此时会分配哈希表buckets数组和entries数组的空间和初始大小,默认为3。对key=1进行哈希求值,假设第一个元素的哈希值=9,然后targetBucket = 9%buckets.Length(3)的值为0,所以第一个元素应该放在entries数组的第一位。最后对哈希表buckets数组赋值,数组索引为0,值为0。此时内部结构如图所示:

mark

然后插入第二个元素,对key=2进行哈希求值,假设第二个元素的哈希值=3,然后targetBucket = 3%buckets.Length (默认是3)的值为0,所以第二个元素应该放在entries数组的第一位。但是entries数组的第一位已经存在元素了,这就发生了冲突。Dictionary<TKey,TValue>解决冲突的方式是链接法,把发生冲突的元素链接之前元素的后面,通过next属性来指定冲突关系,最后更新哈希表buckets数组。此时内部结构如图所示:

mark

我们可以通过Dictionary<TKey,TValue>查找元素的实现来证明我们上面的分析是正确的。

Dictionary<TKey,TValue>查找元素的实现:

mark

mark

SortedDictionary<TKey,TValue>添加新元素的实现:

mark

mark

SortedList<TKey,TValue> 实现

内部实现结构:

mark

根据Key获取Value的实现:

mark

IndexOfKey实现:

mark

添加新元素:

mark

添加操作:

mark

LIst实现

List内部重要变量:

mark

mark

新增元素操作:

mark

新增元素确认数组容量:

mark

2.LinkedList

mark

因为内部实现结构是链表,所以可以在某一个节点前或节点后插入新的元素。

链表节点定义:

mark

我们以在某个节点前插入新元素为例:

mark

具体的插入操作,注意操作步骤不能颠倒:

mark

HashSet

内部实现数据结构:

mark

m_slots中所存放的是Slot结构体,Slot结构体由3个部分组成,如下所示:

mark

添加新元素的具体实现:

Dictionary<TKey,TValue>添加新元素的实现基本一致。

mark

Stack实现:

mark

入栈操作:

mark

弹栈操作:

mark

 

扩展知识:

被代理特性修辞的接口,调试器变量窗口仅显示代理类型的公共成员。

比如:Dictionary<TKey, TValue>实现IDictionary<TKey, TValue> ,ICollection<KeyValuePair<TKey, TValue>>,应该有add()两个重载方法,调试器变量窗口仅显示Add(TKey key, TValue value)方法,经过测试证明另外一个方法也能使用。

 KeyValuePair<TKey,TValue>的用法:结构体,定义可设置或检索的键/值对。也就是说我们可以通过 它记录一个键/值对这样的值。

KeyValuePair<string, string> data1 = new KeyValuePair<string, string>("001", "John");
Console.WriteLine(data1.Key);

msdn的解释:

DebuggerTypeProxyAttribute 指定类型的代理或替身,并更改类型在调试器窗口中的显示方式。 查看具有代理的变量时,代理将代替**“显示”**中的原始类型。 调试器变量窗口仅显示代理类型的公共成员。 不会显示私有成员。

泛型:允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。

非泛型集合装箱和拆箱带来的性能开销问题

键的类型

用作字典中键的类型必须重写Object类的getHashCode()方法,只要字典类需要确定元素位置,就要调用getHashcode()方法。Gethashcode()方法返回的int由字典用于计算在对应位置放置的索引。

字典性能取决于getHashcode()实现代码

不同键对象可能返回相同散列代码,所有必须实现IEqutable<T>.Equals()方法,或重写Object的Equals()方法,

实现Equals方法(),必须实现gethashcode()方法。

Object只比较引用,在字典使用类型不太方便

String实现IEquatable的Equals()方法,重载了getHashCode()方法,字符串用作字典很方便。

Int32实现IEquatable的Equals()方法,重载了getHashCode()方法,但是如果不能分布在可能整数范围内,就不适合字典

可以创建实现IEqualityComparer接口比较器,定义了getHashcode()和Equals()方法,在Dictionary重载版本使用。

参考文献: 

https://blog.csdn.net/a1256242238/article/details/72887731

https://www.cnblogs.com/songwenjie/p/9185790.html

https://www.cnblogs.com/lgx5/p/6955568.html

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值