12.C# —— 经典排序 +(ArrayList / 泛型 List / Dictionary)
目录一、手动实现 Array.Find 功能1. 原理说明2. 完整代码3. 核心逻辑总结二、冒泡排序1. 算法思想2. 代码实现基础版 优化版3. 要点三、选择排序1. 算法思想2. 原生选择排序代码3. 结合 Lambda 使用 Array.Sort官方排序四、非泛型集合 ArrayList1. 基本介绍核心特点和普通数组对比装箱 拆箱2. 常用方法与完整示例3. 缺点总结五、泛型集合 List1. 基本介绍优势对比 ArrayList2. 常用方法 代码示例3. 开发建议六、字典 Dictionary1. 基本介绍2. 常用 API3. 完整代码示例七、全套知识点汇总对比1. 数组 vs ArrayList vs List2. 两大排序对比3. 集合使用优先级开发规范一、手动实现 Array.Find 功能1. 原理说明Array.Find本质遍历数组依次把元素传入条件委托匹配成功立即返回当前元素遍历结束无匹配返回类型默认值。委托Funcint, bool接收一个 int 参数、返回 bool匹配条件健壮性处理判断数组、委托是否为null主动抛出参数空异常和官方Array行为保持一致。2. 完整代码using System; namespace _2自己实现find功能 { internal class Program { static void Main(string[] args) { int[] ages new int[] { 1, 2, 3 }; // 查询第一个偶数 Console.WriteLine(MyArray.Find(ages, v v % 2 0)); // 查询第一个能被3整除的数 Console.WriteLine(MyArray.Find(ages, v v % 3 0)); } } /// summary /// 自定义数组工具类复刻官方Find方法 /// /summary public class MyArray { /// summary /// 查找数组中第一个满足条件的元素 /// /summary /// param namearr源数组/param /// param namematch匹配条件委托/param /// returns匹配元素无匹配返回int默认值0/returns public static int Find(int[] arr, Funcint, bool match) { // 空校验 if (arr null) { throw new ArgumentNullException(array); } if (match null) { throw new ArgumentNullException(match); } // 遍历数组 for (int i 0; i arr.Length; i) { // 执行匹配条件 if (match(arr[i])) { return arr[i]; } } // 遍历完毕未找到返回默认值 return 0; } } }3. 核心逻辑总结先做空判断防止程序崩溃for循环遍历数组每一个元素调用传入的Func委托判断是否满足条件找到第一个匹配项直接return全遍历无匹配返回值类型默认值。二、冒泡排序1. 算法思想相邻两个元素两两比较前 后 则交换位置每一轮遍历都会把当前最大值 “冒泡” 到数组末尾。外层循环控制排序总轮数内层循环控制每一轮相邻元素比较次数优化点每一轮排序后末尾已有序元素无需再比较内层循环次数递减。2. 代码实现基础版 优化版using System; namespace _3冒泡排序 { internal class Program { static void Main(string[] args) { int[] num1 { 1, 2, 3, 4, 57, 8, 8, 9 }; // 优化版冒泡排序推荐 for (int i 0; i num1.Length; i) { // -i跳过后面已经排好序的元素 for (int j 0; j num1.Length - 1 - i; j) { // 前一个数 后一个数交换位置升序 if (num1[j] num1[j 1]) { (num1[j], num1[j 1]) (num1[j 1], num1[j]); } } } Console.WriteLine(string.Join(-, num1)); } } }3. 要点升序num1[j] num1[j1]交换降序num1[j] num1[j1]交换num1.Length - 1 - i核心优化减少无效比较。三、选择排序1. 算法思想每一轮先找到最小值的索引一轮结束后将最小值和当前起始位置元素交换。外层循环确定每一轮的起始位置内层循环从起始位置向后遍历记录最小值下标一轮结束如果最小值下标 起始下标执行交换。2. 原生选择排序代码using System; namespace _4选择排序 { internal class Program { static void Main(string[] args) { int[] nums { 1, 2, 30, 4, 5, 8, 8, 8, 9 }; // 原生选择排序升序 for (int i 0; i nums.Length; i) { int minIndex i; // 假设当前下标为最小值下标 // 从i下一位开始查找更小值 for (int j i 1; j nums.Length; j) { if (nums[j] nums[minIndex]) { minIndex j; // 更新最小值下标 } } // 最小值不在当前位置执行交换 if (minIndex ! i) { (nums[i], nums[minIndex]) (nums[minIndex], nums[i]); } } Console.WriteLine(string.Join(-, nums)); } } }3. 结合 Lambda 使用 Array.Sort官方排序C# 内置Array.Sort支持传入比较委托配合 Lambda 快速实现升降序int[] nums { 1, 2, 30, 4, 5, 8, 8, 8, 9 }; // 1. 升序 Array.Sort(nums, (x, y) x - y); Console.WriteLine(string.Join(-, nums)); // 2. 降序 Array.Sort(nums, (x, y) y - x); Console.WriteLine(string.Join(-, nums)); // 3. 完整判断写法可读性更强 Array.Sort(nums, (x, y) { if (x y) return -1; if (x y) return 1; return 0; });规则返回负数x 排在 y 前面返回正数x 排在 y 后面返回0位置不变四、非泛型集合 ArrayList1. 基本介绍命名空间using System.Collections;ArrayList是动态数组长度可自动扩容弥补普通数组长度固定的缺陷。核心特点和普通数组对比数组长度固定类型安全无装箱拆箱ArrayList长度动态可变存储 object 类型类型不安全存在装箱、拆箱可存放任意类型数据int、string、bool、对象等。装箱 拆箱装箱值类型 → 引用类型存入 ArrayList 时自动发生拆箱引用类型 → 值类型取出强转时发生2. 常用方法与完整示例using System; using System.Collections; namespace _5ArrayList动态集合 { internal class Program { static void Main(string[] args) { int[] ages new int[] { 1, 2, 3, 4, 5 }; ArrayList list1 new ArrayList(); // 1. Add添加单个元素装箱 list1.Add(1); list1.Add(2); list1.Add(3); // 2. 取值 拆箱 Console.WriteLine((int)list1[0]); // 3. AddRange批量添加数组/集合 list1.AddRange(ages); // 4. Contains判断是否包含元素 Console.WriteLine(list1.Contains(1)); // 5. IndexOf获取元素索引 Console.WriteLine(list1.IndexOf(1)); // 6. Remove / RemoveAt删除元素 list1.Remove(1); // 根据元素删除 list1.RemoveAt(0); // 根据索引删除 // 7. 修改元素 list1[0] 张三; // 8. Insert / InsertRange插入元素 list1.Insert(0, 李四); list1.InsertRange(2, ages); // 9. LastIndexOf从后查找索引 Console.WriteLine(list1.LastIndexOf(李四)); // 10. GetRange截取子集视图非独立集合 ArrayList list2 list1.GetRange(0, 3); // 遍历集合 foreach (var item in list1) { Console.WriteLine(item ------); } } } }3. 缺点总结类型不安全编译不校验类型频繁装箱拆箱性能较差现代开发基本被泛型 ListT替代。五、泛型集合 ListT1. 基本介绍命名空间using System.Collections.Generic;ListT是泛型动态集合T代表指定存储类型。优势对比 ArrayList类型安全编译时强制校验类型不能存入其他类型无装箱拆箱执行效率高语法简洁兼容数组 ArrayList 所有常用操作。2. 常用方法 代码示例using System; using System.Collections.Generic; namespace _6泛型集合 { internal class Program { static void Main(string[] args) { // 定义泛型集合只能存 string Liststring list1 new Liststring { 张三, 李四 }; Console.WriteLine(元素总数 list1.Count); // 1. Add / AddRange 添加 list1.Add(1); list1.AddRange(new Liststring { 王五 }); // 2. Remove / RemoveAt / RemoveAll 删除 // list1.Remove(1); // list1.RemoveAt(0); // 按条件删除返回删除个数 Console.WriteLine(list1.RemoveAll(v v.StartsWith(李))); // 3. 索引修改 list1[2] 焦恩俊; // 4. Insert 插入 list1.Insert(4, 何家劲); // 5. ForEach 遍历配合Lambda list1.ForEach(x Console.WriteLine(x)); // 普通foreach遍历 foreach (var item in list1) { Console.WriteLine(item -------); } } } }3. 开发建议日常开发优先使用 ListT不再使用 ArrayList。六、字典 DictionaryTKey, TValue1. 基本介绍命名空间using System.Collections.Generic;字典是键值对集合Key(键) → Value(值)Key唯一不重复可自定义类型int、string 等Value存储对应数据可重复类比加强版数组下标不再局限于 int。2. 常用 APIAdd(Key, Value)添加键值对Remove(Key)根据键删除ContainsKey(Key)判断键是否存在Count获取键值对总数Keys获取所有键集合Values获取所有值集合3. 完整代码示例using System; using System.Collections.Generic; namespace _7字典 { internal class Program { static void Main(string[] args) { // 键int 值string Dictionaryint, string dic new Dictionaryint, string(); // 1. 添加键值对 dic.Add(0, 何润东); dic.Add(1, 周传雄-情歌教父); // 2. 根据键取值 Console.WriteLine(dic[0]); // 3. 删除指定键 dic.Remove(0); // 4. 总数 判断键是否存在 Console.WriteLine(总数 dic.Count); Console.WriteLine(是否包含键0 dic.ContainsKey(0)); // 三种遍历方式 // 遍历所有键 foreach (var key in dic.Keys) { Console.WriteLine(key); } // 遍历所有值 foreach (var val in dic.Values) { Console.WriteLine(val); } // 遍历整个键值对最常用 foreach (var item in dic) { Console.WriteLine($键{item.Key} 值{item.Value}); } // 嵌套字典示例键班级名值学员数组 Dictionarystring, string[] dic1 new Dictionarystring, string[]() { {一班, new string[]{ 马化腾,马云,马斯克} }, {二班, new string[]{ 焦恩俊,严屹宽,霍建华,乔振宇} } }; string[] arr dic1[一班]; Console.WriteLine(string.Join(-, arr)); } } }七、全套知识点汇总对比1. 数组 vs ArrayList vs ListT类型长度类型安全装箱拆箱适用场景普通数组固定安全无长度固定、高性能场景ArrayList动态不安全有旧项目、兼容老代码ListT动态安全无现代开发首选2. 两大排序对比冒泡排序相邻比较、交换频繁逻辑简单适合小规模数据选择排序先找最值再交换交换次数少效率略优于冒泡。3. 集合使用优先级开发规范固定长度、同类型数据 →数组动态长度、同类型数据 →ListT键值映射、一对一查询 →DictionaryTKey,TValue绝不主动使用ArrayList仅做历史了解