10.2.2.2集合类
在命名空间System.Collections中提供的集合类主要有类ArrayList、类Stack、类Hashtable、类BitArray、类Queue、类SortedList。这些类中除BitArray外,有一个共同的特点,就是在这些类的定义中,项的类型都是Object类型,所以允许在这些集合中存储任何c#中合法的类型。这样实现的原因主要是为了让用户使用方便,因为Object是任何类型的基类。其他类型的对象在进入这些集合的时候不需要进行类型转换,因为c#能够进行子类到基类的自动转换。
l ArrayList类其实就是一个数组,只不过这个数组能够按需要动态增加空间。在空间改变时,因为改变的时机不同,算法执行的复杂度可能也不相同。因为ArrayList类就是对数组的一个包装,所以除了具有数组的一般属性与方法外,还有一些自己独有的属性与方法。
表10-3是ArrayList类的属性
表10-3
属性名 | 说明 |
Capacity | 获取或设置 ArrayList 可包含的元素数 |
Count | 获取ArrayList中实际包含的元素数 |
IsFixedSize | 获取一个值,该值指示ArrayList是否具有固定大小 |
IsReadOnly | 获取一个值,该值指示ArrayList是否为只读 |
Item | 获取或设置指定索引处的元素 |
表10-4是ArrayList类特有的一些方法列表
表10-4
方法名 | 功能说明 |
Add | 将对象添加到ArrayList的结尾处 |
AddRange | 将另一个集合的所有元素批量添加到ArrayList的末尾 |
Contains | 确定某元素是否在ArrayList中 |
FixedSize | 返回固定大小的ArrayList,其中的元素允许修改,但不允许添加或移除 |
GetRange | 从源ArrayList中取出其中的一个子集返回 |
Insert | 将元素插入ArrayList的指定索引处 |
InsertRange | 将一个集合整体批量地插入到ArrayList的指定索引处 |
ReadOnly | 返回一个与原ArrayList相同的ArrayList,返回的ArrayList具有只读的性质 |
Remove | 从ArrayList中移除特定对象的第一个匹配项 |
RemoveAt | 在指定索引处移除ArrayList的元素 |
RemoveRange | 从ArrayList中移除一定范围的元素 |
Repeat | 返回一个ArrayList,它的元素是指定值的重复拷贝 |
SetRange | 从指定位置用另一个集合批量覆盖原ArrayList的项的值 |
ToArray | 将ArrayList的元素复制到新数组中 |
TrimToSize | 将容量设置为ArrayList中元素的实际数目 |
在ArrayList类的对象生成的时候,系统在对象内部放置了一个内置的数组,并为该内置数组开辟了一个Capacity大小的空间,随着数据的存储,Count不断变化,当Count等于或者超过Capacity时,系统会给该对象重新开辟一个新的内置数组,并把旧的内置数组的内容赋值过去。算法的复杂度是O(Capacity)。
向ArrayList的对象中插入一个新项,如果插入的位置Location是Count,并且Count小于Capacity时,将新项直接插入ArrayList,如果插入的位置Location不是Count,而且Count+1小于Capacity,则将插入位置后的元素后移,然后插入新项,算法的复杂度是O(Count-Location),如果在第一个元素前插入一个新的元素,算法的复杂度将是O(Count)。总之,ArrayList的运行原理基本同数组的操作。
例子ArrayListSample中演示了ArrayList一些方法与属性的使用。为了显示方便,在该例中首先编写了两个静态的函数,分别用来打印ArrayList的属性与元素。代码如下:
using System;
using System.Collections;//注意这里的命名空间的名称
using System.Linq;
using System.Text;
namespace ArrayListSample
{
class Program
{
static void Main(string[] args)
{
ArrayList al = new ArrayList();
PrintProperty("al",al);
//向al中添加元素
Console.WriteLine("<<<<<<<<<<<<<<<<<向al中添加元素>>>>>>>>>>>>>>>>>");
for(int i=1;i<=5;i++)
{
al.Add(new Point { X = i, Y = i + 2 });
}
PrintProperty("al", al);
PrintArray("al",al);
ArrayList _getfromal = al.GetRange(1, 3);
Console.WriteLine("使用al.GetRange(1, 3),从al的1下标开始,取出3个元素,放入_getfromal");
PrintArray("_getfromal",_getfromal);
al.AddRange(_getfromal);
Console.WriteLine("使用al.AddRange,将_getfromal放入中");
PrintArray("al",al);
Point p = new Point { X = 2, Y = 4 };
Console.WriteLine("al中是否包含点({0},{1}){2}",p.X,p.Y,al.Contains(p));
al.Remove(p);
Console.WriteLine("使用al.Remove,从al中删除({0},{1})", p.X, p.Y);
PrintArray("al",al);
Console.WriteLine("使用al.RemoveRange(2, 3),移除下标是2开始的3个的元素");
al.RemoveRange(2, 3);
PrintArray("al",al);
Console.WriteLine("将下标是3的元素移除");
al.RemoveAt(3);
PrintArray("al",al);
Console.WriteLine("使用ArrayList.FixedSize(al),得到一个具有固定大小的ArrayList");
_getfromal = ArrayList.FixedSize(al);
PrintProperty("_getfromal", _getfromal);
Console.WriteLine("使用ArrayList.ReadOnly(al),得到一个具有只读的ArrayList");
ArrayList _getReadOnly = ArrayList.ReadOnly(al);
PrintProperty("_getReadOnly", _getReadOnly);
Console.WriteLine("使用ArrayList.Repeat(p, 5),得到一个具有具有重复项的ArrayList");
ArrayList repeat = ArrayList.Repeat(p, 5);
PrintArray("repeat",repeat);
PrintProperty("repeat", repeat);
PrintProperty("al", al);
Console.WriteLine("使用TrimToSize(),是的al的容量与实际数据的个数相同");
al.TrimToSize();
PrintProperty("al",al);
Console.ReadKey();
}
/// <summary>
/// 打印ArrayList的属性列表
/// </summary>
/// <param name="name">ArrayList对象的名字</param>
/// <param name="al">ArrayList的集合对象</param>
private static void PrintProperty(string name,ArrayList al)
{
//打印ArrayList的属性
Console.WriteLine("<<<<<<<<<<<<<<<<打印{0}的属性列表>>>>>>>>>>>>>>>>", name);
//打印ArrayList的容量
Console.WriteLine("{0}的容量是:{1}",name, al.Capacity);
//打印ArrayList中元素的个数
Console.WriteLine("{0}中元素的个数是:{1}",name, al.Count);
//打印ArrayList空间是否固定
Console.WriteLine("{0}的空间固定大小?{1}",name, al.IsFixedSize);
//打印ArrayList是否是只读的?
Console.WriteLine("{0}是只读的吗?{1}",name, al.IsReadOnly);
}
/// <summary>
/// 打印ArrayList对象的数据
/// </summary>
/// <param name="name">ArrayList对象的名字</param>
/// <param name="arraylist">ArrayList的集合对象</param>
static void PrintArray(string name,ArrayList arraylist)
{
Console.WriteLine("<<<<<<<<<<<<<<<<打印{0}中的元素>>>>>>>>>>>>>>>>", name);
foreach (Object obj in arraylist)
{
Point p=(Point)obj;
Console.WriteLine("({0},{1})", p.X, p.Y);
}
}
}
}
注意:程序中加边框的语句,在该语句中使用了Contains(Object obj)方法来判断对象obj是否是ArrayList中的元素,因为使用了自定义的类Point的对象作为ArrayList中的元素,在调用该算法的时候,在默认的情况下,将会调用Object对象的Equals方法来判断对象是否相等,然而Object默认的Equals方法对于对象来说,比较的是两个对象是否是同一个引用,因此在自定义的类中,必须重写Equals方法,提供判断两个自定义对象是否相等的算法。否则将不会出现正确的结果。
所以类Point的代码是:
namespace ArrayListSample
{
class Point
{
public int X { get; set; }
public int Y { get; set; }
public override bool Equals(Object p)
{
Point p1 = (Point)p;
return X == p1.X && Y == p1.Y;
}
}
}
程序运行的结果是:
al的容量是:0
al中元素的个数是:0
al的空间固定大小?False
al是只读的吗?False
<<<<<<<<<<<<<<<<<向al中添加元素>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<打印al的属性列表>>>>>>>>>>>>>>>>
al的容量是:8
al中元素的个数是:5
al的空间固定大小?False
al是只读的吗?False
<<<<<<<<<<<<<<<<打印al中的元素>>>>>>>>>>>>>>>>
(1,3)
(2,4)
(3,5)
(4,6)
(5,7)
使用al.GetRange(1, 3),从al的1下标开始,取出3个元素,放入_getfromal
<<<<<<<<<<<<<<<<打印_getfromal中的元素>>>>>>>>>>>>>>>>
(2,4)
(3,5)
(4,6)
使用al.AddRange,将_getfromal放入中
<<<<<<<<<<<<<<<<打印al中的元素>>>>>>>>>>>>>>>>
(1,3)
(2,4)
(3,5)
(4,6)
(5,7)
(2,4)
(3,5)
(4,6)
al中是否包含点(2,4)True
使用al.Remove,从al中删除(2,4)
<<<<<<<<<<<<<<<<打印al中的元素>>>>>>>>>>>>>>>>
(1,3)
(3,5)
(4,6)
(5,7)
(2,4)
(3,5)
(4,6)
使用al.RemoveRange(2, 3),移除下标是2开始的3个的元素
<<<<<<<<<<<<<<<<打印al中的元素>>>>>>>>>>>>>>>>
(1,3)
(3,5)
(3,5)
(4,6)
将下标是3的元素移除
<<<<<<<<<<<<<<<<打印al中的元素>>>>>>>>>>>>>>>>
(1,3)
(3,5)
(3,5)
使用ArrayList.FixedSize(al),得到一个具有固定大小的ArrayList
<<<<<<<<<<<<<<<<打印_getfromal的属性列表>>>>>>>>>>>>>>>>
_getfromal的容量是:8
_getfromal中元素的个数是:3
_getfromal的空间固定大小?True
_getfromal是只读的吗?False
使用ArrayList.ReadOnly(al),得到一个具有只读的ArrayList
<<<<<<<<<<<<<<<<打印_getReadOnly的属性列表>>>>>>>>>>>>>>>>
_getReadOnly的容量是:8
_getReadOnly中元素的个数是:3
_getReadOnly的空间固定大小?True
_getReadOnly是只读的吗?True
使用ArrayList.Repeat(p, 5),得到一个具有具有重复项的ArrayList
<<<<<<<<<<<<<<<<打印repeat中的元素>>>>>>>>>>>>>>>>
(2,4)
(2,4)
(2,4)
(2,4)
(2,4)
<<<<<<<<<<<<<<<<打印repeat的属性列表>>>>>>>>>>>>>>>>
repeat的容量是:5
repeat中元素的个数是:5
repeat的空间固定大小?False
repeat是只读的吗?False
<<<<<<<<<<<<<<<<打印al的属性列表>>>>>>>>>>>>>>>>
al的容量是:8
al中元素的个数是:3
al的空间固定大小?False
al是只读的吗?False
使用TrimToSize(),是的al的容量与实际数据的个数相同
<<<<<<<<<<<<<<<<打印al的属性列表>>>>>>>>>>>>>>>>
al的容量是:3
al中元素的个数是:3
al的空间固定大小?False
al是只读的吗?False