C# 排序列表(SortedList)(保姆级教程)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 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 与其他集合的对比

通过表格对比 SortedListDictionaryList<T> 的核心差异:

特性SortedListDictionary<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 内部使用 两个数组 分别存储键和值,频繁的插入/删除可能导致内存浪费。若需高频率操作,建议评估 SortedDictionaryList<T> 的适用性。


结论

SortedList 是 C# 中 平衡“有序性”与“键值对管理” 的理想选择,尤其适合需要 按顺序遍历动态维护有序数据 的场景。通过本文的讲解,读者应能掌握其基本操作、性能特性及实际应用技巧。在后续开发中,建议根据具体需求对比 DictionaryList<T> 的优劣,以选择最合适的集合类型。

实践建议

  1. 尝试用 SortedList 实现一个 商品库存系统,按价格排序并支持快速查询。
  2. 对比 SortedListSortedDictionary 在插入 10万次数据后的性能差异。

通过不断练习与场景适配,开发者将能更灵活地运用这一工具,提升代码的效率与可读性。

最新发布