C# 排序列表(SortedList)(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
前言
在 C# 的集合类家族中,SortedList
是一个兼具 “字典的键值对特性” 和 “列表的有序性” 的独特类型。它通过动态维护键的排序顺序,为开发者提供了在键值对集合中快速查找、插入和遍历的便利。无论是管理学生信息、商品库存,还是实现需要有序存储的配置系统,SortedList
都能成为得力工具。本文将通过 循序渐进的讲解、形象的比喻 和 实战代码示例,帮助读者掌握这一数据结构的核心原理与应用场景。
一、什么是 SortedList
?
1.1 核心特性与比喻
SortedList
是 C# 中 唯一 同时具备以下特性的集合类型:
- 键值对存储:像
Dictionary<TKey, TValue>
一样,每个元素由键(Key)和值(Value)组成。 - 自动排序:键的顺序始终按照 升序排列(默认按类型自然排序),无需额外调用排序方法。
形象地说,SortedList
就像一个 “图书馆的分类书架”:
- 每本书(键值对)都有唯一的分类号(键)和书名(值)。
- 图书管理员(
SortedList
)会自动将新书按分类号顺序插入,确保读者始终能按顺序浏览书籍。
1.2 与其他集合的对比
通过表格对比 SortedList
与 Dictionary
、List<T>
的核心差异:
特性 | SortedList | Dictionary<TKey, TValue> | List<T> |
---|---|---|---|
键值对 | 是 | 是 | 否(仅存储值) |
自动排序 | 是(按键的顺序) | 否 | 是(需手动排序) |
插入性能 | 较低(需维护顺序) | 较高(哈希表实现) | 高(尾部插入) |
按顺序遍历 | 直接支持 | 需额外排序 | 直接支持 |
二、基础用法与代码实践
2.1 创建与初始化
SortedList
可通过以下方式实例化:
SortedList<int, string> studentScores = new SortedList<int, string>();
// 或使用类型推断(C# 3.0+)
var scores = new SortedList<int, string>();
若需自定义排序规则(如降序),需通过 IComparer<TKey>
接口实现:
var descendingScores = new SortedList<int, string>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
2.2 添加元素
添加元素时,需指定键和值:
studentScores.Add(101, "Alice"); // 添加学号101的学生
studentScores.Add(103, "Bob");
studentScores.Add(102, "Charlie"); // 注意:键的顺序会被自动调整
此时,SortedList
内部会根据键的值 自动排序,实际存储顺序为 101 → 102 → 103
。
2.3 访问元素
可通过键或索引访问值:
// 通过键获取值
string name = studentScores[102]; // Charlie
// 通过索引获取键和值
int key = studentScores.GetKey(1); // 102
string value = studentScores.GetByIndex(1); // Charlie
若键不存在,studentScores[key]
会抛出 KeyNotFoundException
,需通过 ContainsKey()
验证:
if (studentScores.ContainsKey(104)) {
Console.WriteLine(studentScores[104]);
}
2.4 删除元素
删除可通过键或索引完成:
// 通过键删除
studentScores.Remove(103); // 删除Bob
// 通过索引删除
studentScores.RemoveAt(0); // 删除第一个元素(学号101)
三、内部机制与性能分析
3.1 如何保持有序性?
SortedList
的有序性依赖于 “平衡树” 或 “数组+二分查找” 的实现(具体实现细节由 .NET 版本决定)。
- 插入操作:新键会被插入到正确的位置,导致 O(log n) 的时间复杂度(类似二分查找)。
- 查找操作:通过键查找值的时间复杂度为 O(log n),而通过索引访问则为 O(1)。
3.2 与 Dictionary
的性能对比
操作 | SortedList 时间复杂度 | Dictionary 时间复杂度 |
---|---|---|
插入 | O(log n) | O(1)(平均) |
按键查找 | O(log n) | O(1)(平均) |
按索引访问 | O(1) | N/A |
遍历有序性 | 内置支持 | 需额外排序 |
总结:
- 优先选择
SortedList
的场景:需要 有序遍历,且插入/删除操作频率较低。 - 优先选择
Dictionary
的场景:追求 最高性能,且无需维护键的顺序。
四、高级用法与案例
4.1 自定义排序规则
通过 IComparer<TKey>
实现自定义排序:
public class ReverseComparer : IComparer<int> {
public int Compare(int x, int y) => y.CompareTo(x);
}
var descendingList = new SortedList<int, string>(new ReverseComparer());
descendingList.Add(5, "Five");
descendingList.Add(3, "Three"); // 存储顺序为5 →3
4.2 遍历与操作
遍历所有键值对:
foreach (KeyValuePair<int, string> kvp in studentScores) {
Console.WriteLine($"ID: {kvp.Key}, Name: {kvp.Value}");
}
遍历键或值的集合:
foreach (int key in studentScores.Keys) { Console.WriteLine(key); }
foreach (string value in studentScores.Values) { Console.WriteLine(value); }
4.3 实战案例:学生管理系统
假设需要按学号管理学生信息:
class Program {
static void Main() {
SortedList<int, Student> students = new SortedList<int, Student>();
// 添加学生
students.Add(202, new Student { ID = 202, Name = "David" });
students.Add(101, new Student { ID = 101, Name = "Alice" });
// 遍历并打印
foreach (var student in students.Values) {
Console.WriteLine($"学生姓名:{student.Name}, 学号:{student.ID}");
}
}
}
class Student {
public int ID { get; set; }
public string Name { get; set; }
}
输出结果:
学生姓名:Alice, 学号:101
学生姓名:David, 学号:202
五、注意事项与最佳实践
5.1 键的唯一性
SortedList
不允许重复键。尝试添加重复键时会抛出 ArgumentException
,需通过 ContainsKey()
验证:
if (!studentScores.ContainsKey(101)) {
studentScores.Add(101, "Alice");
}
5.2 线程安全
SortedList
不是线程安全的。多线程环境下需通过 lock
或使用 SortedDictionary
(后者设计为线程安全的替代方案)。
5.3 内存占用
SortedList
内部使用 两个数组 分别存储键和值,频繁的插入/删除可能导致内存浪费。若需高频率操作,建议评估 SortedDictionary
或 List<T>
的适用性。
结论
SortedList
是 C# 中 平衡“有序性”与“键值对管理” 的理想选择,尤其适合需要 按顺序遍历 或 动态维护有序数据 的场景。通过本文的讲解,读者应能掌握其基本操作、性能特性及实际应用技巧。在后续开发中,建议根据具体需求对比 Dictionary
和 List<T>
的优劣,以选择最合适的集合类型。
实践建议:
- 尝试用
SortedList
实现一个 商品库存系统,按价格排序并支持快速查询。 - 对比
SortedList
与SortedDictionary
在插入 10万次数据后的性能差异。
通过不断练习与场景适配,开发者将能更灵活地运用这一工具,提升代码的效率与可读性。