C#学习笔记——ArrayList集合

知识点思维导图


00. ArrayList集合

一、集合简介

在C#中,集合框架分为两大类:非泛型集合和泛型集合。这两类集合位于不同的命名空间,各有其适用场景。

1.1、非泛型集合 (System.Collections)

非泛型集合位于System.Collections命名空间下,它们可以存储任何类型的对象,但缺乏类型安全。这意味着在操作时需要进行装箱(将值类型转换为对象)和拆箱(将对象转换回值类型),可能导致性能开销和运行时错误。常见类包括:

  • ArrayList:动态数组,可存储任意对象。
  • Hashtable:键值对集合。
  • Queue:先进先出队列。
  • Stack:后进先出栈。

这些集合适用于早期C#版本或需要处理异构数据的场景,但现代开发中更推荐泛型集合。

1.2、泛型集合 (System.Collections.Generic)

泛型集合位于System.Collections.Generic命名空间下,引入类型参数(如T),提供编译时类型检查,避免装箱/拆箱开销。这提升了性能和安全性。常见类包括:

  • List<T>:类型安全的动态列表。
  • Dictionary<TKey, TValue>:键值对集合。
  • Queue<T>:泛型队列。
  • Stack<T>:泛型栈。

泛型集合是C# 2.0及以后版本的推荐选择,尤其在高性能应用中。


二、ArrayList

ArrayList是非泛型集合的核心代表,它基于数组实现,支持动态扩容。

2.1、ArrayList简介

ArrayList类位于System.Collections命名空间,用于存储对象集合。它允许添加、删除和索引访问元素,但所有元素以object类型存储。这使得ArrayList灵活但类型不安全。例如,存储整数时需要进行装箱:

ArrayList list = new ArrayList();
list.Add(10); // 装箱:int 转换为 object
int num = (int)list[0]; // 拆箱:object 转换为 int

ArrayList的优势在于动态大小:初始容量为0,添加元素时自动扩容(通常翻倍),避免数组的固定大小限制。

2.2、ArrayList的使用

ArrayList提供丰富的属性和方法,便于集合操作。

2.2.1 ArrayList的对象创建

创建ArrayList对象有多种方式:

// 方式1: 默认构造函数,初始容量为0
ArrayList list1 = new ArrayList();

// 方式2: 指定初始容量
ArrayList list2 = new ArrayList(10); // 初始容量为10

// 方式3: 从现有集合初始化
int[] array = {1, 2, 3};
ArrayList list3 = new ArrayList(array); // 将数组转换为ArrayList

2.2.2 ArrayList属性

常用属性包括:

  • Count:获取当前元素数量。
  • Capacity:获取或设置内部数组的容量(可优化内存使用)。
  • IsFixedSize:返回false,表示大小可变。
  • IsReadOnly:返回false,表示可修改。

示例:

ArrayList list = new ArrayList();
list.Add("A");
Console.WriteLine(list.Count); // 输出: 1
Console.WriteLine(list.Capacity); // 输出: 0 (初始状态)

2.2.3 ArrayList常用的方法

ArrayList支持多种操作方法,以下是核心功能:

  1. 添加元素

    • Add(object value):在末尾添加元素,平均时间复杂度为$O(1)$(扩容时为$O(n)$)。
    • Insert(int index, object value):在指定索引插入元素,时间复杂度$O(n)$。

    示例:

    ArrayList list = new ArrayList();
    list.Add("Apple"); // 添加元素
    list.Insert(0, "Banana"); // 在索引0处插入
    

  2. 删除元素

    • Remove(object value):删除第一个匹配元素。
    • RemoveAt(int index):删除指定索引元素。
    • Clear():清空所有元素。

    示例:

    list.Remove("Apple"); // 删除"Apple"
    list.RemoveAt(0); // 删除索引0元素
    list.Clear(); // 清空列表
    

  3. 查找元素

    • Contains(object value):检查元素是否存在。
    • IndexOf(object value):返回第一个匹配索引(-1表示未找到)。

    示例:

    bool exists = list.Contains("Banana"); // true或false
    int index = list.IndexOf("Apple"); // 返回索引或-1
    

  4. ArrayList的索引器(I操作) ArrayList支持索引访问,类似于数组:

    list[0] = "Orange"; // 设置索引0元素
    string item = (string)list[0]; // 获取索引0元素(需类型转换)
    

    索引器的时间复杂度为$O(1)$,但使用时需注意类型安全风险。

2.3、ArrayList与数组的区别

ArrayList和数组(如int[])在C#中有显著差异,以下是关键对比点:

  1. 类型系统

    • 数组:类型安全,编译时检查元素类型(如int[]只能存储整数)。
    • ArrayList:非类型安全,存储object类型,需要装箱/拆箱。
  2. 大小特性

    • 数组:固定大小,声明后长度不可变。
    • ArrayList:动态大小,自动扩容(通过Capacity属性管理)。
  3. 性能比较

    • 数组:访问速度快($O(1)$),无额外开销。
    • ArrayList:添加/删除元素可能触发扩容($O(n)$),且装箱/拆箱增加开销。例如,存储值类型时,ArrayList的性能低于数组。
  4. 类型安全

    • 数组:编译时类型检查,避免运行时错误。
    • ArrayList:无编译时检查,可能导致InvalidCastException
  5. 初始化方式

    • 数组:直接初始化(如int[] arr = {1, 2, 3};)。
    • ArrayList:需通过构造函数或方法添加元素。
  6. 功能方法

    • 数组:基本功能有限(如Length属性)。
    • ArrayList:提供丰富方法(如Add, Remove, Sort)。
  7. 使用场景对比

    • 数组:适用于固定大小、类型一致的数据(如数学计算)。
    • ArrayList:适用于动态数据、混合类型场景(如旧版代码兼容)。
  8. 内存分配示例

    • 数组:连续内存块,高效但不可变。
    • ArrayList:基于数组实现,扩容时分配新数组并复制元素,内存开销更大。

    示例:ArrayList扩容过程:

    ArrayList list = new ArrayList(2); // 初始容量2
    list.Add(1); // 使用现有容量
    list.Add(2);
    list.Add(3); // 触发扩容:新容量=4,复制元素
    


三、List<T>泛型列表

List<T>是泛型集合的代表,提供类型安全和高效操作。

3.1 ArrayList与List<T>的相同与不同点

List<T>与ArrayList有相似功能,但关键差异在于类型处理:

  • 相同点:两者都是动态数组,支持添加、删除、索引访问和扩容机制。
  • 不同点
    • 类型安全:List<T>使用类型参数(如List<int>),编译时检查,避免装箱/拆箱。
    • 性能:List<T>操作更快(无装箱开销),平均时间复杂度类似(如Add为$O(1)$)。
    • 命名空间:List<T>位于System.Collections.Generic,ArrayList位于System.Collections
    • 初始化:List<T>支持集合初始化器(如new List<int> {1, 2, 3})。
3.2 List<T>常用操作

List<T>提供直观的API,以下是基础操作:

  1. 创建 List

    List<int> numbers = new List<int>(); // 空列表
    List<string> names = new List<string>() {"Alice", "Bob"}; // 初始化
    

  2. 添加元素

    • Add(T item):末尾添加。
    • Insert(int index, T item):指定索引插入。

    示例:

    numbers.Add(10); // 添加元素
    numbers.Insert(0, 5); // 在索引0插入5
    

  3. 访问元素 使用索引器直接访问:

    int first = numbers[0]; // 获取索引0元素
    numbers[1] = 20; // 设置索引1元素
    

  4. 常用方法

    • Remove(T item):删除元素。
    • RemoveAt(int index):删除索引元素。
    • Contains(T item):检查存在性。
    • Count属性:获取元素数量。

    示例:

    numbers.Remove(10); // 删除值为10的元素
    bool hasFive = numbers.Contains(5); // true或false
    

  5. 遍历 List 使用循环遍历:

    foreach (int num in numbers) {
        Console.WriteLine(num);
    }
    // 或 for 循环
    for (int i = 0; i < numbers.Count; i++) {
        Console.WriteLine(numbers[i]);
    }
    

3.3 高级操作

List<T>支持复杂操作,提升数据处理效率。

  1. 排序

    • Sort()方法:使用默认比较器排序(升序)。
    • 自定义排序:通过Comparison<T>委托。

    示例:

    List<int> values = new List<int> {3, 1, 2};
    values.Sort(); // 升序排序:1,2,3
    
    // 自定义降序排序
    values.Sort((a, b) => b.CompareTo(a));
    

  2. 查找

    • Find(Predicate<T> match):返回第一个匹配元素。
    • FindAll(Predicate<T> match):返回所有匹配元素。
    • BinarySearch(T item):有序列表中二分查找(高效$O(\log n)$)。

    示例:

    List<string> fruits = new List<string> {"Apple", "Banana", "Orange"};
    string result = fruits.Find(f => f.StartsWith("B")); // "Banana"
    List<string> allB = fruits.FindAll(f => f.Length > 5); // ["Banana","Orange"]
    

  3. 转换

    • ConvertAll<TOutput>(Converter<T, TOutput> converter):将列表元素转换为新类型。
    • 使用LINQ转换(如Select)。

    示例:

    List<int> nums = new List<int> {1, 2, 3};
    List<string> strings = nums.ConvertAll(x => x.ToString()); // ["1","2","3"]
    


总结

C# 中的集合分为非泛型(如 System.Collections 下的 ArrayList)和泛型两大类。非泛型的 ArrayList 以 object 类型存储任意元素,虽具备动态扩容的便利,但值类型必须装箱/拆箱,既损失性能又缺乏编译时类型检查;与固定大小的数组相比,它更灵活,但内存开销和运行时类型转换风险也更高。而泛型 List<T> 通过类型参数保证了类型安全,完全避免了装箱/拆箱,操作速度更快,同时提供了同样丰富的增删改查、排序、查找及转换等功能,是现代 C# 开发中处理动态数组的首选。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值