0

0

c++的std::set和std::unordered_set该如何取舍? (有序与哈希)

穿越時空

穿越時空

发布时间:2026-01-28 11:43:02

|

673人浏览过

|

来源于php中文网

原创

需顺序遍历时必须用std::set,因其红黑树实现保证升序;仅查存在性时优先unordered_set,平均O(1)查找但依赖哈希质量;key不可比较则选unordered_set,不可哈希则只能用set。

c++的std::set和std::unordered_set该如何取舍? (有序与哈希)

需要按顺序遍历或取范围时,必须用 std::set

如果你要频繁做 lower_boundupper_boundequal_range,或者需要迭代器保证升序(比如打印所有元素、做归并操作),std::set 是唯一选择。它底层是红黑树,天然有序,begin()end() 就是从小到大。

std::unordered_set 的迭代器顺序完全不确定,每次插入/删除后都可能变,不能依赖遍历顺序。

  • std::set 支持 key_comp() 自定义比较逻辑,能轻松实现字典序、长度优先等复合排序
  • std::unordered_set 即使你重载了 operator== 和哈希函数,也无法提供任何顺序保证
  • 若误把 unordered_set 当作有序容器用(比如想“取前 5 个最小值”),结果会随机且不可重现

只关心存在性判断和单点查找时,优先选 std::unordered_set

查一个元素在不在集合里,find()count() 操作,std::unordered_set 平均是 O(1)std::setO(log n)。数据量大时差距明显——比如百万级元素,前者平均几次哈希+比较,后者要 20 层树跳转。

但要注意:这个“平均 O(1)”依赖哈希函数质量。如果大量键映射到同一桶(哈希冲突严重),性能会退化成 O(n)

立即学习C++免费学习笔记(深入)”;

码上飞
码上飞

码上飞(CodeFlying) 是一款AI自动化开发平台,通过自然语言描述即可自动生成完整应用程序。

下载
  • 内置类型(intstd::string)的默认哈希通常够用;自定义结构体必须显式提供好哈希特化(std::hash
  • 插入顺序不影响查找效率,但极端情况下(如全哈希到同一个桶),unordered_set 可能比 set 还慢
  • 内存占用通常更高:unordered_set 要预留空桶、维护指针链表;set 每节点只存 key + 3 个指针

元素类型不支持严格弱序比较时,不能用 std::set

std::set 要求 key 类型可比较(满足 Strict Weak Ordering),比如必须能用 比较两个对象,并满足自反性、传递性等。很多类型默认没定义 operator,比如 std::vector、自定义结构体、std::shared_ptr 等。

这时要么手动写比较器(lambda 或 functor),要么改用 unordered_set —— 它只要求可哈希(std::hash)和可相等(operator==),门槛更低。

  • 例如:用 std::vector 当 key,set 需要传入 lambda:
    std::set, std::less<>> s;
    (C++14 起 std::less 支持泛型调用)
  • unordered_set 必须特化 std::hash<:vector>>,否则编译失败
  • 没有比较器也不打算写?那 set 直接不可用,别硬扛

内存受限或对最坏性能敏感时,std::set 更可控

std::unordered_set 的 rehash 行为是隐式的:当负载因子超过 max_load_factor()(默认 1.0),它会重新分配更大 bucket 数组,并把所有元素 rehash 过去。这是一次 O(n) 操作,可能卡住实时逻辑。

std::set 插入始终是 O(log n),无突发开销,内存增长也平滑(每个节点单独 new)。

  • 可用 reserve(n) 预分配 bucket,但无法完全避免 rehash;rehash(n) 可强制扩容,但需预估容量
  • set 的内存局部性差(指针跳转多),unordered_set 的 bucket 数组连续,缓存友好——但前提是哈希分布均匀
  • 调试时,unordered_set 的内部结构(桶数组+链表)比红黑树更难 inspect,GDB / IDE 显示也不直观
实际选型往往不是非此即彼:先问自己三个问题—— 是否需要顺序?是否只查存在性?key 类型能否方便地比较或哈希? 多数时候答案会自然指向一个。但别忽略 rehash 的毛刺、哈希碰撞的陷阱、以及调试时多花的那半小时。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Sass和less的区别
Sass和less的区别

Sass和less的区别有语法差异、变量和混合器的定义方式、导入方式、运算符的支持、扩展性等。本专题为大家提供Sass和less相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.10.12

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

463

2023.08.02

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.11.20

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

220

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

192

2025.07.04

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

463

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

544

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

93

2025.08.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

2

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.9万人学习

C 教程
C 教程

共75课时 | 4.3万人学习

C++教程
C++教程

共115课时 | 14.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号