基础概念
SortedSet 是 C# 中的一个集合类型,位于 System.Collections.Generic 命名空间下。它是一个自动排序的集合,用于存储不重复的元素,并且会根据元素的自然顺序(默认排序)或自定义比较器进行排序,内部使用红黑树数据结构来维护元素的有序性。
- 自动排序:每次添加或删除元素时,SortedSet 都会自动调整以保持元素的排序状态。
- 不重复元素:SortedSet 不允许重复的元素。如果尝试添加一个已经存在的元素,该操作会被忽略。
- 高效性 :SortedSet 内部使用红黑树 (一种自平衡二叉搜索树)实现,因此查找、插入和删除操作的时间复杂度为 O(log n)。
主要特性
- 自动保持元素排序:元素会根据其自然顺序(需实现 IComparable<T> 接口)或自定义比较器(IComparer<T>)排序。
- 不包含重复元素:尝试添加已有元素时,Add 方法返回 false,集合保持不变。
- 支持集合操作:提供并集、交集、差集等操作。
- 支持子集视图:可以通过方法获取某个范围内的元素。
- 快速访问边界值:提供 Min 和 Max 属性,快速获取最小和最大元素。
创建和初始化
基本创建方式
-
使用默认比较器(升序)
*cs// 使用默认比较器(升序) SortedSet<int> numbers = new SortedSet<int>();
-
使用自定义比较器
*cs// 使用自定义比较器 SortedSet<string> names = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
-
从现有集合创建
*cs// 从现有集合创建 int[] array = { 5, 2, 8, 1, 9 }; SortedSet<int> sortedNumbers = new SortedSet<int>(array); // 结果:{1, 2, 5, 8, 9}
-
使用集合初始化器
*cs// 使用集合初始化器 SortedSet<string> fruits = new SortedSet<string> { "Apple", "Banana", "Cherry" };
自定义比较器
-
降序排列
*cs// 降序排列 SortedSet<int> descendingNumbers = new SortedSet<int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));
-
自定义对象排序
*cs// 自定义对象排序 public class Person : IComparable<Person> { public string Name { get; set; } public int Age { get; set; } public int CompareTo(Person other) { if (other == null) return 1; return this.Age.CompareTo(other.Age); // 按年龄排序 } } SortedSet<Person> people = new SortedSet<Person>();
-
使用自定义比较器
*cs// 或使用自定义比较器 SortedSet<Person> peopleByName = new SortedSet<Person>( Comparer<Person>.Create((p1, p2) => string.Compare(p1.Name, p2.Name)) );
基本操作
添加和删除元素
cs
SortedSet<int> numbers = new SortedSet<int>();
-
添加元素
*cs// 添加元素 bool added1 = numbers.Add(5); // true,成功添加 bool added2 = numbers.Add(3); // true,成功添加 bool added3 = numbers.Add(5); // false,元素已存在 Console.WriteLine(string.Join(", ", numbers)); // 输出:3, 5
-
删除元素
*cs// 删除元素 bool removed = numbers.Remove(3); // true,成功删除 numbers.Remove(10);
-
清空集合
*cs// 清空集合 numbers.Clear();
查询操作
cs
SortedSet<int> numbers = new SortedSet<int> { 1, 3, 5, 7, 9 };
-
检查元素是否存在
*cs// 检查元素是否存在 bool contains = numbers.Contains(5); // true
-
获取元素数量
*cs// 获取元素数量 int count = numbers.Count; // 5
-
检查是否为空
*cs// 检查是否为空 bool isEmpty = numbers.Count == 0; // false
-
获取最小值和最大值
*cs// 获取最小值和最大值 int min = numbers.Min; // 1 int max = numbers.Max; // 9
范围查询
- 使用 GetViewBetween 方法获取指定范围内的元素子集
cs
SortedSet<int> numbers = new SortedSet<int> { 1, 3, 5, 7, 9, 11, 13 };
// 获取视图(不创建新集合)
SortedSet<int> subset1 = numbers.GetViewBetween(3, 9);
// 结果:{3, 5, 7, 9}
SortedSet<int> subset2 = numbers.GetViewBetween(4, 10);
// 结果:{5, 7, 9}
// 视图会反映原集合的变化
numbers.Add(6);
Console.WriteLine(string.Join(", ", subset2)); // 输出:5, 6, 7, 9
集合运算
并集、交集、差集
cs
SortedSet<int> set1 = new SortedSet<int> { 1, 2, 3, 4, 5 };
SortedSet<int> set2 = new SortedSet<int> { 4, 5, 6, 7, 8 };
-
并集: UnionWith 将另一个集合的元素合并到 SortedSet 中。
*cs// 并集(修改 set1) set1.UnionWith(set2); Console.WriteLine(string.Join(", ", set1)); // 1, 2, 3, 4, 5, 6, 7, 8
-
交集: IntersectWith 保留与另一个集合的交集。
*cs// 重新初始化 set1 = new SortedSet<int> { 1, 2, 3, 4, 5 }; // 交集(修改 set1) set1.IntersectWith(set2); Console.WriteLine(string.Join(", ", set1)); // 4, 5
-
差集: ExceptWith 删除与另一个集合相交的元素。
*cs// 重新初始化 set1 = new SortedSet<int> { 1, 2, 3, 4, 5 }; // 差集(set1 中有但 set2 中没有的元素) set1.ExceptWith(set2); Console.WriteLine(string.Join(", ", set1)); // 1, 2, 3
-
对称差集: SymmetricExceptWith 两个集合中不共同拥有的元素
*cs// 对称差集(两个集合中不共同拥有的元素) set1 = new SortedSet<int> { 1, 2, 3, 4, 5 }; set1.SymmetricExceptWith(set2); Console.WriteLine(string.Join(", ", set1)); // 1, 2, 3, 6, 7, 8
集合关系判断
cs
SortedSet<int> set1 = new SortedSet<int> { 1, 2, 3 };
SortedSet<int> set2 = new SortedSet<int> { 1, 2, 3, 4, 5 };
SortedSet<int> set3 = new SortedSet<int> { 2, 3 };
SortedSet<int> set4 = new SortedSet<int> { 6, 7 };
-
子集判断
*cs// 子集判断 bool isSubset = set1.IsSubsetOf(set2); // true bool isProperSubset = set1.IsProperSubsetOf(set2); // true bool isSuperset = set2.IsSupersetOf(set1); // true bool isProperSuperset = set2.IsProperSupersetOf(set1); // true
-
重叠判断
*cs// 重叠判断 bool overlaps = set1.Overlaps(set3); // true(有共同元素2,3) bool overlaps2 = set1.Overlaps(set4); // false(无共同元素)
-
相等判断
*cs// 相等判断 bool areEqual = set1.SetEquals(set3); // false
遍历和枚举
基本遍历
cs
SortedSet<string> fruits = new SortedSet<string> { "Banana", "Apple", "Cherry" };
-
foreach 遍历(按排序顺序)
*cs// foreach 遍历(按排序顺序) foreach (string fruit in fruits) { Console.WriteLine(fruit); // Apple, Banana, Cherry }
-
使用枚举器
*cs// 使用枚举器 using (var enumerator = fruits.GetEnumerator()) { while (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); } }
反向遍历
cs
SortedSet<int> numbers = new SortedSet<int> { 1, 3, 5, 7, 9 };
// 反向遍历
foreach (int number in numbers.Reverse())
{
Console.WriteLine(number); // 9, 7, 5, 3, 1
}
SortedSet 的优点和适用场景
优点
- 自动保持元素排序,无需手动干预。
- 确保元素唯一性,避免重复。
- 高效的操作性能(O(log n))。
- 支持集合操作和子集视图。
适用场景
- 需要有序且不重复的元素集合,例如排行榜、时间线。
- 实现优先级队列(尽管 C# 有 PriorityQueue<T>)。
- 执行集合操作,如并集、交集等。
SortedSet 与其他集合类型的区别
- 与 HashSet<T> 的区别 :
- HashSet<T> 不保持顺序,查找时间为 O(1)。
- SortedSet<T> 保持顺序,查找时间为 O(log n)。
- 与 List<T> 的区别 :
- List<T> 允许重复元素,不自动排序。
- SortedSet<T> 不允许重复,自动排序。
- 与 SortedList<TKey, TValue> 的区别 :
- SortedList<TKey, TValue> 是键值对集合,键排序。
- SortedSet<T> 是元素集合,元素本身排序。