一、C# 中 HashSet、Dictionary<TKey,TValue> 底层数据结构
二者底层均基于哈希表(Hash Table) 实现,但用途、存储形式完全不同:
1. HashSet
所属结构:哈希集合(无序不重复集合)
核心特点
- 存储单一元素,只有值、没有键;
- 强制元素全局唯一,不允许重复存入相同对象;
- 无序存储,不维持插入顺序(.NET Core 以后版本会保留近似插入顺序,但规范上不承诺有序);
- 底层:数组 + 链表/红黑树(哈希桶)
- 根据元素哈希码
GetHashCode()计算桶下标,放入对应哈希桶; - 哈希冲突:早期链表串联冲突元素;.NET 5+ 冲突过多会转为红黑树提升查询效率;
- 根据元素哈希码
- 时间复杂度:
- 添加、删除、查找:平均 O(1),最坏 O(n)
- 典型场景:去重、集合运算(交集、并集、差集)、判断元素是否存在
2. Dictionary<TKey, TValue>
所属结构:哈希映射 / 键值对哈希表
核心特点
- 存储 Key-Value 键值对:唯一键映射一个值;
- 约束:
Key不可重复,Value 可以重复; - 同样无序,依靠键的哈希码寻址;
- 底层结构和 HashSet 几乎一致:哈希桶数组存放键值对条目,冲突处理逻辑完全相同;
本质可以理解为:Dictionary = HashSet<Key>额外绑定了一个附属Value; - 时间复杂度:按键增删查平均 O(1);
- 典型场景:键值映射、缓存、根据主键快速取值
二者核心区别汇总
| 特性 | HashSet | Dictionary<TKey,TValue> |
|---|---|---|
| 存储内容 | 单个元素 | 键+值配对 |
| 唯一性约束 | 所有元素唯一 | 仅Key唯一 |
| 访问方式 | 遍历全体 / 包含判断 | 通过Key索引取值 |
| 底层 | 哈希表 | 哈希表 |
二、C++ 中对应等价容器(STL标准库)
C++ STL 分为两套:哈希无序容器(C++11 及以后)、有序平衡树容器(旧标准)
C++ 没有直接叫 HashSet/Dictionary 的类,靠无序哈希容器一一对应
1. C++ 对应 C# HashSet:std::unordered_set<T>
底层结构:哈希表(哈希桶 + 链表处理冲突)
关键特性
- 无序、元素不可重复,完全对标 C# HashSet;
- 增删查平均 O(1);
- 头文件:
#include <unordered_set>
简单示例
#include <unordered_set>
std::unordered_set<int> uset;
uset.insert(1);
uset.count(1); // 判断是否存在,等价HashSet.Contains()
uset.erase(1);
备选有序版本(基于红黑树,非哈希)
std::set<T>:底层红黑树(平衡二叉搜索树),元素有序、唯一,增删查 O(logn),不属于哈希结构,效率低于无序哈希集合。
2. C++ 对应 C# Dictionary<TKey,TValue>:std::unordered_map<K, V>
底层结构:哈希表,键值对存储,对标 Dictionary
关键特性
- Key唯一,Value随意;无序排布;
- 按键查找、插入、删除平均 O(1);
- 头文件:
#include <unordered_map>
简单示例
#include <unordered_map>
std::unordered_map<std::string, int> umap;
umap["age"] = 20; // 赋值
int val = umap["age"]; // 按键取值
umap.count("age"); // 判断键是否存在
备选有序版本(红黑树实现)
std::map<K,V>:底层红黑树,按键自动升序排列,操作复杂度 O(logn),有序但速度慢于哈希表。
三、完整对照一览表
| C# 类型 | 底层结构 | C++ 哈希等价容器 | C++ 有序树容器 |
|---|---|---|---|
HashSet<T> |
哈希表 | std::unordered_set<T> |
std::set<T> |
Dictionary<TK,TV> |
哈希表 | std::unordered_map<TK,TV> |
std::map<TK,TV> |
补充细节差异
- 哈希冲突处理
- C#:链表 + 超高冲突转红黑树
- C++ unordered_xxx:默认单向链表串联冲突元素,不会自动转红黑树
- 自定义类型哈希
C# 重写GetHashCode()+Equals;
C++ 需要自定义哈希函数传入模板参数; - 顺序保障
所有unordered_容器都不保证插入顺序;set/map按键排序。