C#语言 第三部分 集合框架 IList,IList——向量(1)

来源:互联网 发布:php网页游戏源代码 编辑:程序博客网 时间:2024/06/05 07:54

向量是一个可以动态改变长度的数组,起作用就是无需确定集合的初始长度,集合会随着存放数据的数量自行变化。

.net Framwork中提供了两种向量的规范:

  • 集合元素类型为Object类型的IList接口,可以存放不同类型的对象引用;
  • 以泛型为基础的IList<T>接口,只能存放一种类型的对象引用。

下图展示了IList接口及IList<T>接口的继承层次


图1 IList及IList<T>继承层次图

一、IList接口

1.1 接口特点:

IList接口从ICollection接口继承,所以其具备如下特性:

  • 可获取集合元素个数 - Count属性;
  • 可迭代 - GetEnumerator方法(从IEnumerable接口继承);
  • 集合元素传递给数组 - CopyTo方法。

IList接口添加了如下特性:

  • 访问集合任意索引所在元素 - this[]索引器属性;
  • 向集合末尾添加元素 - Add方法;
  • 向集合特定位置插入元素 - Insert方法;
  • 删除特定元素 - Remove方法;
  • 删除索引位置特定的元素 - RemoveAt方法;
  • 判断对象是否在集合中被引用 - Contains方法;
  • 查找特定对象在集合中的索引位置 - IndexOf方法;
  • 清空整个集合 - Clear方法。

IList类型集合按照顺序存放元素(所谓顺序即IList类型集合不会改变元素的存放顺序)。

1.2 IList<T>接口 

IList<T>接口从ICollection<T>接口继承,所以其具备如下特性:

  • 可获取集合元素个数 - Count属性;
  • 可迭代 - GetEnumerator方法(从IEnumerable接口继承);
  • 集合元素传递给数组 - CopyTo方法;
  • 向集合末尾添加元素 - Add方法;
  • 删除特定元素 - Remove方法;
  • 判断对象是否在集合中被引用 - Contains方法;
  • 清空整个集合 - Clear方法。

IList<T>接口添加了如下特性:

  • 访问集合任意索引所在元素 - this[]索引器属性
  • 向集合特定位置插入元素 - Insert方法;
  • 删除索引位置特定的元素 - RemoveAt方法;
  • 查找特定对象在集合中的索引位置 - IndexOf方法;

IList<T>类型集合按照顺序存放特定类型元素

二、算法

另外,向量集合和数组一样,具备随机访问特点。即无论访问向量集合的任何一个单元,所需的访问时间是完全相同的。C#的IList/IList<T>接口表现出C++中vector<T>的特性。

  • 实际应用中,我们大多使用泛型向量,因为它更安全且高效。

在向量类中,依然使用普通数组来记录集合数据,只是向量使用了一些算法技巧,让整个类对外表现不同于普通数组的重要特点可以动态的改变数组长度,具体算法要点如下:

在内部数组长度足够的情况下,直接进行添加或插入操作(必要时需要数据搬移);
在内部数组长度不足的情况下,按照内部数组长度加1的2倍作为新数组的长度分配新数组,进行必要数据搬移,进行添加或插入操作;
在数据删除时,并不改变内部数组的长度,而仅仅是使用被删除数据之后的数据覆盖被删除数据即可。

向量再分配元素存储空间时,使用了典型的空间换时间原则,即每次空间不足的时候,都多分配一些冗余空间,以求最低限度的减少内存分配次数。内存分配是程序性能的一个瓶颈,应尽量避免集中的次数繁多的内存分配。

三、实现类

.net Framework提供了IList和IList<T>的实现类,它们是ArrayList类List<T>类,其中:

  • ArrayList类处于System.Collections命名空间下;
  • List<T>类处于System.Collections.Specialized命名空间下。

四、一个IList接口的实现(源代码)

ArrayList.cs

仔细观察上述代码,弄清楚两个问题:

  1. 迭代子类(17 - 67行)是如何实现的,其内部原理是什么?
  2. 向量是如何存储对象引用的,存储分配的算法(163 - 164行)是什么?

另外还要注意的索引器的使用(203行),利用索引器可以表现出来更优美的语法;

可以采用如下代码测试ArrayList类:

Program.cs

原创粉丝点击