C# 集合(Collection)
一、集合概述
C# 集合是用于数据存储和检索的类,主要用于动态管理数据(如动态分配内存、灵活增删元素等)。大多数集合类实现了相同的接口(如IEnumerable
、ICollection
等),支持栈、队列、列表、哈希表等数据结构。
集合与数组的核心区别:
特性 | 数组(Array) | 集合(Collection) |
---|---|---|
类型限制 | 固定类型(object[] 除外) | 部分类型固定(如List<T> ),部分可存任意类型(如ArrayList ) |
长度特性 | 固定长度,创建后不可变 | 动态长度,可自动扩容 / 缩容 |
内存布局 | 连续内存块 | 非连续(多数集合) |
性能 | 访问速度快(直接索引) | 增删改效率高(避免数组扩容开销) |
装箱拆箱 | 无(值类型直接存储) | 非泛型集合有(如ArrayList 存储值类型时) |
二、常用集合类型详解
1. 动态数组(ArrayList)
命名空间:
System.Collections
特性:
类型不固定:可存储任意类型数据(值类型需装箱,取出需拆箱)
长度不固定:动态扩容 / 缩容
常用属性:
Count
:获取元素个数
常用方法:
Add(object value)
:末尾添加元素AddRange(ICollection c)
:末尾添加集合元素Insert(int index, object value)
:指定索引插入元素Remove(object value)
:删除第一个匹配元素Clear()
:清空所有元素Contains(object value)
:判断是否包含指定元素
示例关键操作:
ArrayList list = new ArrayList() { 1, "hello", true }; // 存储任意类型 list.Add(3.14); // 动态添加 Console.WriteLine(list[0]); // 通过索引访问(返回object类型,需强转) foreach (var item in list) { ... } // 遍历
2. 泛型集合(List<T>)
命名空间:
System.Collections.Generic
特性:
类型固定:仅能存储指定类型(
T
),避免装箱拆箱长度不固定:动态扩容
常用属性:
Count
:元素个数
常用方法:
基础方法:
Add(T item)
、AddRange(IEnumerable<T> collection)
、Insert(int index, T item)
等(与ArrayList
类似)高阶方法:
Find(Predicate<T> match)
、FindAll(Predicate<T> match)
、Sort()
等
示例关键操作:
List<int> nums = new List<int>() { 1, 2, 3 }; // 仅存int类型 nums.Add(4); int first = nums.Find(n => n > 2); // 查找第一个大于2的元素
3. 字典(Dictionary<TKey, TValue>)
命名空间:
System.Collections.Generic
特性:
键值对存储:每个元素包含
Key
(键)和Value
(值)键唯一:同一字典中键不可重复
类型固定:键和值的类型由
TKey
和TValue
指定
常用属性:
Count
:键值对个数Keys
:获取所有键的集合Values
:获取所有值的集合
常用方法:
Add(TKey key, TValue value)
:添加键值对(键重复会报错)Remove(TKey key)
:删除指定键的键值对ContainsKey(TKey key)
:判断是否包含指定键TryGetValue(TKey key, out TValue value)
:安全获取值(避免键不存在时报错)
示例关键操作:
Dictionary<string, int> dict = new Dictionary<string, int>() { { "a", 1 }, { "b", 2 } }; Console.WriteLine(dict["a"]); // 通过键访问值 foreach (KeyValuePair<string, int> item in dict) {Console.WriteLine($"键:{item.Key},值:{item.Value}"); // 遍历键值对 }
4. 哈希表(Hashtable)
命名空间:
System.Collections
特性:
键值对存储:键和值均为
object
类型(可存任意类型)键唯一:通过哈希算法快速查找(类似
Dictionary
的非泛型版本)
常用属性:
Count
:元素个数Keys
:所有键的集合Values
:所有值的集合
常用方法:
Add(object key, object value)
:添加键值对Remove(object key)
:删除指定键的元素ContainsKey(object key)
:判断是否包含指定键
示例关键操作:
Hashtable ht = new Hashtable() { { 1, "one" }, { "two", 2 } }; Console.WriteLine(ht[1]); // 访问值(需注意类型转换)
5. 排序列表(SortedList)
命名空间:
System.Collections
特性:
键值对存储,自动按键排序(升序)
支持双重访问:通过索引(类似数组)或键(类似哈希表)访问
键类型必须一致(否则无法排序,会报错)
常用属性:
Count
:元素个数Capacity
:容量(可手动设置)
常用方法:
Add(object key, object value)
:添加键值对(自动排序)GetByIndex(int index)
:通过索引获取值(索引 0 对应最小键的元素)GetKey(int index)
:通过索引获取键
示例关键操作:
SortedList sl = new SortedList() { { 3, "c" }, { 1, "a" }, { 2, "b" } }; Console.WriteLine(sl.GetByIndex(0)); // 输出"a"(键1最小,索引0) Console.WriteLine(sl[3]); // 输出"c"(通过键访问)
6. 堆栈(Stack)
命名空间:
System.Collections
特性:
后进先出(LIFO):最后添加的元素最先被移除
操作术语:入栈(
Push
)、出栈(Pop
)、查看栈顶(Peek
)
常用属性:
Count
:元素个数
常用方法:
Push(object obj)
:入栈(添加到栈顶)Pop()
:出栈(移除并返回栈顶元素)Peek()
:查看栈顶元素(不删除)
示例关键操作:
Stack stack = new Stack(); stack.Push(1); stack.Push(2); // 栈顶为2 Console.WriteLine(stack.Pop()); // 输出2(栈顶元素出栈)
7. 队列(Queue)
命名空间:
System.Collections
特性:
先进先出(FIFO):最先添加的元素最先被移除
操作术语:入队(
Enqueue
)、出队(Dequeue
)
常用属性:
Count
:元素个数
常用方法:
Enqueue(object obj)
:入队(添加到队尾)Dequeue()
:出队(移除并返回队首元素)Peek()
:查看队首元素(不删除)
示例关键操作:
Queue queue = new Queue(); queue.Enqueue("a"); queue.Enqueue("b"); // 队首为"a",队尾为"b" Console.WriteLine(queue.Dequeue()); // 输出"a"(队首元素出队)
三、集合对比总结
集合类型 | 类型是否固定 | 长度是否固定 | 核心特性 | 长度表示 | 典型用途 |
---|---|---|---|---|---|
数组(Array) | 固定 | 固定 | 连续内存,索引访问快 | Length | 存储固定长度、同类型数据 |
ArrayList | 不固定 | 不固定 | 动态数组,可存任意类型 | Count | 存储无类型限制的动态数据 |
List<T> | 固定(T ) | 不固定 | 泛型动态列表,类型安全 | Count | 存储同类型动态数据(推荐) |
Dictionary<TKey,TValue> | 固定 | 不固定 | 键值对,键唯一,查询快 | Count | 需通过键快速查找值的场景 |
Hashtable | 不固定 | 不固定 | 非泛型键值对,哈希查找 | Count | 兼容旧代码的键值对存储 |
SortedList | 键类型固定 | 不固定 | 键值对,自动按键排序 | Count | 需要排序的键值对场景 |
Stack | 不固定 | 不固定 | 后进先出(LIFO) | Count | 回溯、表达式求值等 |
Queue | 不固定 | 不固定 | 先进先出(FIFO) | Count | 消息队列、任务调度等 |
四、作业解析
1. 求集合中数字的平均值
// 思路:用List<int>存储数字,求和后除以元素个数 List<int> nums = new List<int>() { 1, 2, 3, 4, 5 }; int sum = 0; foreach (int num in nums) sum += num; double avg = (double)sum / nums.Count; Console.WriteLine("平均值:" + avg); // 输出3
2. 生成 10 个不重复的随机数(0-9)
// 思路:用HashSet(自动去重)或List+Contains检查重复 Random random = new Random(); List<int> result = new List<int>(); while (result.Count < 10) {int num = random.Next(0, 10); // 生成0-9的随机数if (!result.Contains(num)) { // 检查是否重复result.Add(num);} } // 输出结果 foreach (int num in result) Console.Write(num + " ");
3. 分离数组中的奇数和偶数并输出
// 思路:遍历数组,按奇偶分入两个集合 int[] num = { 1, 3, 5, 6, 8, 100, 20, 11 }; List<int> odds = new List<int>(); // 奇数集合 List<int> evens = new List<int>(); // 偶数集合 foreach (int n in num) {if (n % 2 == 1) odds.Add(n);else evens.Add(n); } // 输出:奇数在左,偶数在右 foreach (int o in odds) Console.Write(o + " "); Console.Write(" | "); foreach (int e in evens) Console.Write(e + " "); // 输出:1 3 5 11 | 6 8 100 20
4. 将用户输入的字符串转为字符数组
// 思路:通过foreach遍历字符串,逐个字符添加到数组 Console.WriteLine("请输入字符串:"); string input = Console.ReadLine(); char[] chars = new char[input.Length]; // 初始化与字符串等长的字符数组 int index = 0; foreach (char c in input) {chars[index] = c;index++; } // 验证输出 foreach (char c in chars) Console.Write(c + " ");
5. 删除数组中重复的值
// 思路:用HashSet去重(自动过滤重复),再转回数组 string[] stringArray = { "aaa", "bbb", "aaa", "ccc", "bbb", "ddd", "ccc", "aaa", "bbb", "ddd" }; HashSet<string> uniqueSet = new HashSet<string>(stringArray); // 去重 string[] result = uniqueSet.ToArray(); // 转回数组 // 输出去重后结果 foreach (string s in result) Console.Write(s + " "); // 输出:aaa bbb ccc ddd (顺序可能不同)