C#进阶学习(七)常见的泛型数据结构类(2)HashSet和SortedSet

目录

[using System.Collections.Generic; // 核心命名空间](#using System.Collections.Generic; // 核心命名空间)

[一、 HashSet](#一、 HashSet)

核心特性

常用方法

属性

二、SortedSet

核心特性

[1、整型(int、long 等)](#1、整型(int、long 等))

2、字符串型(string)

3、字符型(char)

4、自定义对象

常用方法

属性

[三、 HashSet](#三、 HashSet) [和 SortedSet 方法对比表](#和 SortedSet 方法对比表)

共有方法

独有方法

四、HashSet中的自定义相等方法与SortedSet中的自定义排序方式的示例

4-1HashSet示例,不区分大小写:

4-2SortedSet自定义比较器(按字符串长度排序和倒序排数字)

五、总结


注意本文提到的数据结构需在比较新的.NET框架上使用,不然会出错

必须引用的命名空间:

using System.Collections.Generic; // 核心命名空间

一、 HashSet<T>

核心特性

  • 唯一性 :保证集合中元素的唯一性(通过 GetHashCodeEquals 判断重复)。

  • 无序性:元素的存储和遍历顺序与插入顺序无关,也不保证任何特定顺序。

  • 底层实现 :基于哈希表(Hash Table),使用桶(Buckets)和链表/开放寻址解决哈希冲突。

  • 适用场景:快速判断元素是否存在、去重、集合运算(并集、交集、差集)。

创造方式:

cs 复制代码
// 默认构造函数
var hashSet1 = new HashSet<int>();

// 从集合初始化
var hashSet2 = new HashSet<int>(new[] { 1, 2, 3 });

// 指定自定义相等比较器
var hashSet3 = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

常用方法

方法名 参数 返回值/行为 示例代码
Add(T item) 要添加的元素 返回 bool(是否添加成功) hashSet.Add(5);
Remove(T item) 要删除的元素 返回 bool(是否删除成功) hashSet.Remove(2);
Contains(T item) 要检查的元素 返回 bool(是否包含元素) if (hashSet.Contains(3)) { ... }
Clear() 清空所有元素 hashSet.Clear();
UnionWith(IEnumerable<T>) 另一个集合 将当前集合修改为与另一个集合的并集 hashSet.UnionWith(otherSet);
IntersectWith(IEnumerable<T>) 另一个集合 将当前集合修改为与另一个集合的交集 hashSet.IntersectWith(otherSet);
ExceptWith(IEnumerable<T>) 另一个集合 将当前集合修改为当前集合减去另一个集合(差集) hashSet.ExceptWith(otherSet);
SymmetricExceptWith(IEnumerable<T>) 另一个集合 将当前集合修改为仅包含存在于当前集合或另一集合但不同时存在的元素(对称差集) hashSet.SymmetricExceptWith(otherSet);
IsSubsetOf(IEnumerable<T>) 另一个集合 返回 bool(当前集合是否是另一个集合的子集) bool isSubset = hashSet.IsSubsetOf(otherSet);
IsSupersetOf(IEnumerable<T>) 另一个集合 返回 bool(当前集合是否是另一个集合的超集) bool isSuperset = hashSet.IsSupersetOf(otherSet);
Overlaps(IEnumerable<T>) 另一个集合 返回 bool(当前集合与另一个集合是否有交集) bool overlaps = hashSet.Overlaps(otherSet);
SetEquals(IEnumerable<T>) 另一个集合 返回 bool(当前集合是否与另一个集合元素完全相同) bool equals = hashSet.SetEquals(otherSet);
CopyTo(T[] array) 目标数组 将集合元素复制到数组中 int[] arr = new int[10]; hashSet.CopyTo(arr);
TryGetValue(T equalValue, out T actualValue) 查找的值 equalValue 如果找到相等元素,返回 true 并赋值给 actualValue if (hashSet.TryGetValue(5, out int val)) { ... }

主要使用演示:

cs 复制代码
using System;
using System.Collections.Generic;

public class HashSetExample
{
    public static void Main()
    {
        // 初始化 HashSet
        Console.WriteLine("---------------------------------1、初始化--------------------------------------------");
        var hashSet = new HashSet<int> { 1, 2, 3 };
        Console.WriteLine("初始集合: " + string.Join(", ", hashSet)); // 输出: 1, 2, 3

        Console.WriteLine("---------------------------------2、增加元素--------------------------------------------");
        // 添加元素
        bool added = hashSet.Add(4);
        Console.WriteLine($"添加 4 成功?{added}"); // true

        added = hashSet.Add(2);
        Console.WriteLine($"重复添加 2 成功?{added}"); // false

        Console.WriteLine("---------------------------------3、查找元素--------------------------------------------");
        // 检查元素存在性
        Console.WriteLine("是否包含 3?" + hashSet.Contains(3)); // true

        Console.WriteLine("---------------------------------4、删除元素--------------------------------------------");
        // 删除元素
        bool removed = hashSet.Remove(2);
        Console.WriteLine($"删除 2 成功?{removed}"); // true

        Console.WriteLine("---------------------------------5、集合运算--------------------------------------------");
        // 集合运算
        var otherSet = new HashSet<int> { 3, 4, 5 };

        // 并集(合并两个集合的元素)
        hashSet.UnionWith(otherSet);
        Console.WriteLine("并集后: " + string.Join(", ", hashSet)); // 1, 3, 4, 5

        // 交集(保留共同元素)
        hashSet.IntersectWith(new[] { 3, 4 });
        Console.WriteLine("交集后: " + string.Join(", ", hashSet)); // 3, 4

        // 差集(移除当前集合中与另一集合重复的元素)
        hashSet.ExceptWith(new[] { 3 });
        Console.WriteLine("差集后: " + string.Join(", ", hashSet)); // 4

        // 对称差集(仅保留不重复的元素)
        hashSet.SymmetricExceptWith(new[] { 4, 5, 6 });
        Console.WriteLine("对称差集后: " + string.Join(", ", hashSet)); // 5, 6

        Console.WriteLine("---------------------------------6、获取存在的元素使用--------------------------------------------");
        // TryGetValue(查找元素)
        if (hashSet.TryGetValue(5, out int value))
        {
            Console.WriteLine($"找到元素: {value}"); // 5
        }
        Console.WriteLine("---------------------------------7、清空元素--------------------------------------------");
        // 清空集合
        hashSet.Clear();
        Console.WriteLine("清空后元素数量: " + hashSet.Count); // 0
    }
}

属性

属性名 类型 说明 示例代码
Count int 集合中元素的数量 int count = hashSet.Count;
Comparer IEqualityComparer<T> 用于比较元素的相等性比较器 var comparer = hashSet.Comparer;

这个比较器,主要是用来自定义相同规则

二、SortedSet<T>

核心特性

  • 唯一性:保证元素唯一性。

  • 有序性 :元素按升序 自动排列(默认使用 IComparer<T> 或元素的自然顺序)。

  • 底层实现 :基于红黑树(Red-Black Tree),一种自平衡二叉搜索树。

  • 适用场景:需要有序唯一元素的集合、范围查询(如获取某个区间内的元素)。

这个排序指的是怎么个排序法则呢:

SortedSet<T> 默认按元素的 自然顺序(IComparable<T> 接口)排序

看都看不懂上面那句话,来我们接着往下看,对于不同的类型具有不同的排序方式:

1、整型(intlong 等)

按数值升序排列。

示例:{ 5, 3, 9 } → 排序后为 { 3, 5, 9 }

2、字符串型(string

按字典序(区分大小写)排序。

示例:{ "Banana", "apple", "Cherry" } → 排序后为 { "Banana", "Cherry", "apple" }(ASCII 值:B=66, C=67, a=97)。

3、字符型(char

按 Unicode 码点升序排序。

示例:{ 'C', 'a', '1' } → 排序后为 { '1' (U+0031), 'C' (U+0043), 'a' (U+0061) }

4、自定义对象

若未实现 IComparable<T>,需通过构造函数指定 IComparer<T>,否则会抛出异常。

初始化方式:

cs 复制代码
// 默认构造函数(按自然顺序排序)
var sortedSet1 = new SortedSet<int>();

// 从集合初始化
var sortedSet2 = new SortedSet<int>(new[] { 3, 1, 2 });

// 指定自定义比较器
var sortedSet3 = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);

常用方法

方法名 参数 返回值/行为 示例代码
Add(T item) 要添加的元素 返回 bool(是否添加成功) sortedSet.Add(5);
Remove(T item) 要删除的元素 返回 bool(是否删除成功) sortedSet.Remove(2);
Contains(T item) 要检查的元素 返回 bool(是否包含元素) if (sortedSet.Contains(3)) { ... }
Clear() 清空所有元素 sortedSet.Clear();
UnionWith(IEnumerable<T>) 另一个集合 将当前集合修改为与另一个集合的并集 sortedSet.UnionWith(otherSet);
IntersectWith(IEnumerable<T>) 另一个集合 将当前集合修改为与另一个集合的交集 sortedSet.IntersectWith(otherSet);
ExceptWith(IEnumerable<T>) 另一个集合 将当前集合修改为当前集合减去另一个集合(差集) sortedSet.ExceptWith(otherSet);
SymmetricExceptWith(IEnumerable<T>) 另一个集合 将当前集合修改为仅包含存在于当前集合或另一集合但不同时存在的元素(对称差集) sortedSet.SymmetricExceptWith(otherSet);
GetViewBetween(T lower, T upper) 下限 lower 和上限 upper 返回一个子集视图,包含介于 lowerupper 之间的元素 var subset = sortedSet.GetViewBetween(2, 5);
CopyTo(T[] array) 目标数组 将集合元素复制到数组中 int[] arr = new int[10]; sortedSet.CopyTo(arr);
Reverse() 返回一个按降序排列的 IEnumerable<T> foreach (var item in sortedSet.Reverse()) { ... }

使用演示:

cs 复制代码
using System;
using System.Collections.Generic;

public class SortedSetExample
{
    public static void Main()
    {
        Console.WriteLine("---------------------------------1、初始化--------------------------------------------");
        // 初始化 SortedSet(默认升序)
        var sortedSet = new SortedSet<int> { 5, 2, 8, 1 };
        Console.WriteLine("初始集合: " + string.Join(", ", sortedSet)); // 1, 2, 5, 8

        Console.WriteLine("---------------------------------2、添加元素--------------------------------------------");
        // 添加元素
        bool added = sortedSet.Add(3);
        Console.WriteLine($"添加 3 成功?{added}"); // true

        added = sortedSet.Add(2);
        Console.WriteLine($"重复添加 2 成功?{added}"); // false

        Console.WriteLine("---------------------------------3、查询是否存在某个元素--------------------------------------------");
        // 检查元素存在性
        Console.WriteLine("是否包含 5?" + sortedSet.Contains(5)); // true

        Console.WriteLine("---------------------------------4、删除某一个元素--------------------------------------------");
        // 删除元素
        bool removed = sortedSet.Remove(8);
        Console.WriteLine($"删除 8 成功?{removed}"); // true

        Console.WriteLine("---------------------------------5、集合运算--------------------------------------------");
        // 集合运算
        var otherSet = new SortedSet<int> { 3, 4, 5 };

        // 并集
        sortedSet.UnionWith(otherSet);
        Console.WriteLine("并集后: " + string.Join(", ", sortedSet)); // 1, 2, 3, 4, 5

        // 交集
        sortedSet.IntersectWith(new[] { 2, 3, 4 });
        Console.WriteLine("交集后: " + string.Join(", ", sortedSet)); // 2, 3, 4

        // 范围查询(获取介于 3 和 5 之间的元素视图)
        var subset = sortedSet.GetViewBetween(3, 5);
        Console.WriteLine("范围查询结果: " + string.Join(", ", subset)); // 3, 4

        Console.WriteLine("---------------------------------5、最大值最小值--------------------------------------------");
        // 直接获取最小值和最大值
        Console.WriteLine($"最小值: {sortedSet.Min}, 最大值: {sortedSet.Max}"); // 2, 4

        // 逆序遍历(降序)
        Console.Write("逆序遍历: ");
        foreach (var num in sortedSet.Reverse())
        {
            Console.Write(num + " "); // 4, 3, 2
        }
        Console.WriteLine();

        // 清空集合
        sortedSet.Clear();
        Console.WriteLine("清空后元素数量: " + sortedSet.Count); // 0
    }
}

属性

属性名 类型 说明 示例代码
Count int 集合中元素的数量 int count = sortedSet.Count;
Comparer IComparer<T> 用于排序元素的比较器 var comparer = sortedSet.Comparer;
Min T 集合中的最小元素 int min = sortedSet.Min;
Max T 集合中的最大元素 int max = sortedSet.Max;

三、 HashSet<T>SortedSet<T> 方法对比表

共有方法

方法名 HashSet<T> 支持 SortedSet<T> 支持 说明
Add(T) ✔️ ✔️ 添加元素
Remove(T) ✔️ ✔️ 删除元素
Contains(T) ✔️ ✔️ 检查元素是否存在
Clear() ✔️ ✔️ 清空集合
UnionWith(IEnumerable<T>) ✔️ ✔️ 并集操作
IntersectWith(IEnumerable<T>) ✔️ ✔️ 交集操作
ExceptWith(IEnumerable<T>) ✔️ ✔️ 差集操作
SymmetricExceptWith(IEnumerable<T>) ✔️ ✔️ 对称差集操作
CopyTo(T[]) ✔️ ✔️ 复制到数组

独有方法

方法名 HashSet<T> 特有 SortedSet<T> 特有 说明
TryGetValue(T, out T) ✔️ 查找并返回元素(哈希表特性)
GetViewBetween(T, T) ✔️ 获取子集视图(有序特性)
Reverse() ✔️ 返回降序迭代器(有序特性)
Min / Max ✔️ 直接获取最小/最大值(有序特性)

四、HashSet中的自定义相等方法与SortedSet中的自定义排序方式的示例

4-1HashSet示例,不区分大小写:

第一步,实现一个IEqualityComparer接口
cs 复制代码
//比较接口
public class InsensitiveComparer : IEqualityComparer<string>
{
    //判断两个字符串是否相等 不判断类型
    public bool Equals(string? x, string? y)
    {
        //使用系统给我们实现好的 直接忽略大小写
        return string.Equals(x,y,StringComparison.OrdinalIgnoreCase);
    }

    //生成字符串的哈希码(不区分大小写)
    public int GetHashCode([DisallowNull] string obj)
    {
        //将字符串统一转为大写后生成哈希码
        return obj.ToUpper().GetHashCode();
    }
}
第二步,在初始化集合时new 一个接口,这里是里氏替换原则哦
cs 复制代码
HashSet<string> haseSetString = new HashSet<string>(new InsensitiveComparer())
{
    "Apple","apple","Banana"
};
Console.WriteLine(haseSetString.Count);
Console.WriteLine(haseSetString.Contains("APPLE"));

4-2SortedSet自定义比较器(按字符串长度排序和倒序排数字)

第一步、实现IComparer接口:
cs 复制代码
public class StringLengthComparer : IComparer<string>
{
    public int Compare(string? x, string? y)
    {
        // 按长度升序,若长度相同则按字典序
        int lengthCompare = x.Length.CompareTo(y.Length);
        return lengthCompare != 0 ? lengthCompare : string.Compare(x, y, StringComparison.Ordinal);
    }
}

public class ReverseIntComparer : IComparer<int>
{
    public int Compare(int x, int y)
    {
        // 默认升序是 x.CompareTo(y),降序则反转
        //y 比较与 x
        //谁小 谁放前
        return y.CompareTo(x);
    }
}
第二步、初始化时new 一个接口对象
cs 复制代码
//1.自定义字符串长度使用
var sortedSetString = new SortedSet<string>(new StringLengthComparer())
{
    "Banana", "Apple", "Cherry", "Kiwi"
};
Console.WriteLine("按长度排序:");
foreach (var item in sortedSet)
{
    Console.WriteLine(item); // 输出顺序:Kiwi → Apple → Banana → Cherry
}

//2.倒序排数字
// 使用自定义比较器初始化 SortedSet
var sortedSetInt = new SortedSet<int>(new ReverseIntComparer())
{
    5, 3, 9, 1
};

Console.WriteLine("降序排序:");
foreach (var num in sortedSetInt)
{
    Console.Write(num + " "); // 输出:9 5 3 1
}
#endregion

五、总结

HashSet<T> 的核心是快速查找和集合运算 ,适用于无序唯一集合

SortedSet<T> 的核心是维护有序性和范围查询,适用于需要排序的场景。

两者共享大部分集合操作方法,但 SortedSet<T> 额外提供有序相关的功能(如 MinMaxGetViewBetween)。

根据需求选择:

速度优先HashSet<T>

顺序优先SortedSet<T>

相关推荐
a东方青30 分钟前
vue3学习笔记之属性绑定
vue.js·笔记·学习
Pasregret1 小时前
迭代器模式:统一不同数据结构的遍历方式
数据结构·迭代器模式
豆芽8191 小时前
科学研究:怎么做
学习·科研·学习方法
摸鱼 特供版1 小时前
智能翻译播放器,让无字幕视频不再难懂
windows·学习·电脑·音视频·软件需求
豆豆1 小时前
day28 学习笔记
图像处理·笔记·opencv·学习·计算机视觉
开开心心就好2 小时前
实用电脑工具,轻松实现定时操作
python·学习·pdf·电脑·word·excel·生活
SuperCandyXu2 小时前
leetcode0113. 路径总和 II - medium
数据结构·c++·算法·leetcode
硬匠的博客2 小时前
C++继承与派生
数据结构·算法
面包圈蘸可乐2 小时前
论文学习:《创新编码策略的多类LncRNA亚细胞定位的集成深度学习框架》
人工智能·深度学习·学习
purrrew2 小时前
【数据结构_11】二叉树(3)
java·数据结构