====== 第四章 数组与集合 ======
===== 4.1 数组 =====
=== 数组基础 ===
数组是固定大小的、相同类型元素的连续集合。
// 声明和初始化
int[] numbers = new int[5]; // 声明长度为5的数组
int[] scores = { 85, 90, 78, 92, 88 }; // 声明并初始化
string[] names = new string[] { "Alice", "Bob", "Charlie" };
// 访问元素
Console.WriteLine(scores[0]); // 85
scores[1] = 95; // 修改元素
// 数组长度
Console.WriteLine(scores.Length); // 5
=== 多维数组 ===
// 二维数组
int[,] matrix = new int[3, 4];
int[,] table = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
// 访问
Console.WriteLine(table[0, 0]); // 1
Console.WriteLine(table[1, 2]); // 6
// 获取维度长度
Console.WriteLine(table.GetLength(0)); // 3行
Console.WriteLine(table.GetLength(1)); // 3列
// 遍历
for (int i = 0; i < table.GetLength(0); i++)
{
for (int j = 0; j < table.GetLength(1); j++)
{
Console.Write($"{table[i, j]} ");
}
Console.WriteLine();
}
=== 交错数组 ===
// 交错数组(数组的数组)
int[][] jagged = new int[3][];
jagged[0] = new int[] { 1, 2 };
jagged[1] = new int[] { 3, 4, 5 };
jagged[2] = new int[] { 6 };
// 初始化语法
int[][] jagged2 = new int[][]
{
new int[] { 1, 2 },
new int[] { 3, 4, 5, 6 },
new int[] { 7, 8, 9 }
};
// 遍历
foreach (int[] row in jagged)
{
foreach (int num in row)
{
Console.Write(num + " ");
}
Console.WriteLine();
}
=== 数组方法 ===
int[] arr = { 3, 1, 4, 1, 5, 9, 2, 6 };
// 排序
Array.Sort(arr); // [1, 1, 2, 3, 4, 5, 6, 9]
// 反转
Array.Reverse(arr); // [9, 6, 5, 4, 3, 2, 1, 1]
// 查找
int index = Array.IndexOf(arr, 5); // 返回5的索引
int lastIndex = Array.LastIndexOf(arr, 1);
// 二分查找(数组必须先排序)
int found = Array.BinarySearch(arr, 5);
// 清空
Array.Clear(arr, 0, 3); // 将前3个元素设为0
// 复制
int[] copy = new int[arr.Length];
Array.Copy(arr, copy, arr.Length);
int[] clone = (int[])arr.Clone();
===== 4.2 ArrayList与List =====
=== ArrayList(非泛型) ===
using System.Collections;
ArrayList list = new ArrayList();
list.Add(1); // 添加整数
list.Add("Hello"); // 添加字符串
list.Add(3.14); // 添加浮点数
// 缺点:需要装箱拆箱,类型不安全
int num = (int)list[0]; // 需要强制转换
=== List(泛型,推荐使用) ===
using System.Collections.Generic;
// 创建List
List numbers = new List();
List names = new List { "Alice", "Bob", "Charlie" };
// 添加元素
numbers.Add(10);
numbers.AddRange(new[] { 20, 30, 40 });
// 插入
numbers.Insert(0, 5); // 在索引0处插入5
// 删除
numbers.Remove(10); // 删除第一个值为10的元素
numbers.RemoveAt(0); // 删除索引0的元素
numbers.RemoveAll(x => x > 25); // 删除所有大于25的元素
// 查找
bool contains = numbers.Contains(20);
int index = numbers.IndexOf(20);
int foundIndex = numbers.FindIndex(x => x > 15);
int found = numbers.Find(x => x > 15);
// 排序和反转
numbers.Sort();
numbers.Sort((a, b) => b.CompareTo(a)); // 降序排序
numbers.Reverse();
// 其他操作
numbers.Clear();
int count = numbers.Count;
int capacity = numbers.Capacity;
===== 4.3 Dictionary =====
// 创建字典
Dictionary ages = new Dictionary();
Dictionary capitals = new Dictionary
{
{ "中国", "北京" },
{ "美国", "华盛顿" },
{ "日本", "东京" }
};
// 添加
ages.Add("Alice", 25);
ages["Bob"] = 30; // 添加或更新
// 安全添加
if (!ages.ContainsKey("Charlie"))
{
ages.Add("Charlie", 35);
}
// 访问
int aliceAge = ages["Alice"];
// 安全访问
if (ages.TryGetValue("Alice", out int age))
{
Console.WriteLine($"Alice的年龄: {age}");
}
// 遍历
foreach (var pair in capitals)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
foreach (string key in capitals.Keys)
{
Console.WriteLine(key);
}
foreach (string value in capitals.Values)
{
Console.WriteLine(value);
}
// 删除
ages.Remove("Alice");
ages.Clear();
===== 4.4 其他常用集合 =====
=== HashSet ===
// 集合:无序、不重复
HashSet set = new HashSet();
set.Add(1);
set.Add(2);
set.Add(1); // 重复,不会添加
Console.WriteLine(set.Count); // 2
// 集合运算
HashSet set1 = new HashSet { 1, 2, 3, 4 };
HashSet set2 = new HashSet { 3, 4, 5, 6 };
set1.IntersectWith(set2); // 交集: {3, 4}
set1.UnionWith(set2); // 并集
set1.ExceptWith(set2); // 差集
set1.SymmetricExceptWith(set2); // 对称差集
=== Queue ===
// 队列:先进先出(FIFO)
Queue queue = new Queue();
queue.Enqueue("First"); // 入队
queue.Enqueue("Second");
queue.Enqueue("Third");
string first = queue.Dequeue(); // 出队: "First"
string peek = queue.Peek(); // 查看队首但不移除: "Second"
int count = queue.Count;
=== Stack ===
// 栈:后进先出(LIFO)
Stack stack = new Stack();
stack.Push("First"); // 压栈
stack.Push("Second");
stack.Push("Third");
string top = stack.Pop(); // 出栈: "Third"
string peek = stack.Peek(); // 查看栈顶: "Second"
int count = stack.Count;
=== SortedList ===
// 按键排序的字典
SortedList sortedList = new SortedList();
sortedList.Add("Charlie", 3);
sortedList.Add("Alice", 1);
sortedList.Add("Bob", 2);
// 遍历时按键排序
foreach (var pair in sortedList)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
// 输出: Alice, Bob, Charlie
===== 4.5 LINQ基础 =====
=== LINQ简介 ===
LINQ(Language Integrated Query)是集成在C#中的查询语言。
using System.Linq;
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
=== 查询语法 ===
// 查询语法
var evenNumbers = from n in numbers
where n % 2 == 0
select n;
// 排序
var sorted = from n in numbers
orderby n descending
select n;
// 多条件
var result = from n in numbers
where n > 3 && n < 8
orderby n
select n;
=== 方法语法 ===
// Where过滤
var evenNumbers = numbers.Where(n => n % 2 == 0);
// Select投影
var squares = numbers.Select(n => n * n);
// 排序
var sorted = numbers.OrderBy(n => n);
var sortedDesc = numbers.OrderByDescending(n => n);
// 多级排序
var students = new[]
{
new { Name = "Alice", Grade = 90, Class = "A" },
new { Name = "Bob", Grade = 85, Class = "B" },
new { Name = "Charlie", Grade = 90, Class = "A" }
};
var ordered = students
.OrderBy(s => s.Class)
.ThenByDescending(s => s.Grade);
=== 常用LINQ操作 ===
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 聚合
int sum = nums.Sum();
double avg = nums.Average();
int max = nums.Max();
int min = nums.Min();
int count = nums.Count();
int countEven = nums.Count(n => n % 2 == 0);
// 量化
bool hasAny = nums.Any();
bool hasEven = nums.Any(n => n % 2 == 0);
bool allPositive = nums.All(n => n > 0);
bool containsFive = nums.Contains(5);
// 分区
var first3 = nums.Take(3); // 前3个
var skip3 = nums.Skip(3); // 跳过前3个
var takeWhile = nums.TakeWhile(n => n < 5);
// 去重
var distinct = new[] { 1, 2, 2, 3, 3, 3 }.Distinct();
// 转换
List list = nums.ToList();
int[] array = list.ToArray();
Dictionary dict = nums.ToDictionary(n => n, n => n * n);
===== 4.6 Span和Memory(C# 7.2+) =====
// Span: 安全的内存切片,栈上分配
void ProcessSpan()
{
int[] arr = { 1, 2, 3, 4, 5 };
Span span = arr; // 整个数组
Span slice = arr.AsSpan(1, 3); // 切片 [2, 3, 4]
span[0] = 100; // 修改会影响原数组
// 栈上分配的Span
Span stackSpan = stackalloc int[10];
}
// Memory: 堆上分配,可用于异步操作
async Task ProcessMemoryAsync()
{
byte[] data = await File.ReadAllBytesAsync("file.txt");
Memory memory = data;
Memory slice = memory.Slice(10, 100);
}
===== 4.7 集合初始化器 =====
// 集合初始化器
var list = new List { 1, 2, 3, 4, 5 };
var dict = new Dictionary
{
["one"] = 1,
["two"] = 2,
["three"] = 3
};
// 对象集合
var people = new List
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 }
};
// C# 6+ 索引初始化器
var numbers = new Dictionary
{
[1] = "one",
[2] = "two",
[3] = "three"
};
===== 练习题 =====
=== 基础练习 ===
1. **数组操作**:创建一个整数数组,实现以下功能:
- 找出最大值和最小值
- 计算平均值
- 找出第二大的数
- 将数组按升序排序后反转
2. **矩阵运算**:编写方法实现两个二维矩阵的加法和乘法。
3. **List操作**:创建一个字符串List,完成以下操作:
- 添加10个名字
- 删除所有以"A"开头的名字
- 按字母顺序排序
- 查找包含字母"e"的所有名字
=== 进阶练习 ===
4. **学生成绩系统**:使用Dictionary存储学生姓名和成绩,实现:
- 添加学生成绩
- 查询学生成绩
- 计算班级平均分
- 找出最高分和最低分的学生
- 按成绩排序输出
5. **集合运算**:给定两个整数数组,找出:
- 同时存在于两个数组中的元素(交集)
- 只存在于第一个数组中的元素(差集)
- 存在于任一数组中的所有不同元素(并集)
6. **队列实现**:使用Queue实现一个任务调度器,支持:
- 添加任务
- 执行任务(出队)
- 查看待处理任务数
- 清空所有任务
=== 挑战练习 ===
7. **LINQ综合应用**:给定一个Product类(Id, Name, Category, Price),使用LINQ实现:
- 按类别分组统计数量和平均价格
- 找出每个类别中最贵的产品
- 筛选价格高于平均价的产品
- 实现分页查询
8. **自定义集合**:实现一个简单的泛型集合类MyList,支持:
- 添加元素
- 索引访问
- 枚举器(实现IEnumerable)
- 自动扩容
9. **数据统计**:使用数组或List存储一组实验数据,实现:
- 计算均值、中位数、众数
- 计算方差和标准差
- 找出异常值(超过3倍标准差的数据点)
===== 本章小结 =====
本章学习了C#的数组和集合:
- 一维数组、多维数组和交错数组
- Array类的方法和操作
- 泛型集合List、Dictionary
- 专用集合HashSet、Queue、Stack
- LINQ的基础查询语法和方法语法
- Span和Memory的高效内存操作
选择合适的集合类型对于程序性能至关重要。