C++ set怎么去重 C++集合容器自动排序去重原理【数据结构】

发布时间 - 2026-01-31 00:00:00    点击率:
set插入自动去重依赖红黑树的二分查找与等价判断(非相等),要求比较函数满足严格弱序;若自定义类型仅重载operator==而未提供operator

set 插入时自动去重靠的是 std::less 和等价判断

不是靠“查重后再插入”,而是靠红黑树的插入逻辑:每次插入先按排序规则(默认 std::less)做二分查找,若已存在「等价」元素(即既不小于也不大于),就直接丢弃。这里的关键是「等价」≠「相等」——对 int 没区别,但自定义类型若只重载了 operator== 却没适配比较函数,set 仍会插入“看似重复”的元素。

常见错误现象:set 插入两个字段完全相同的对象,结果 size 变成 2。原因往往是只写了 operator==,却没提供 operator 或自定义 Compare 函数对象。

  • 必须确保比较函数满足严格弱序(strict weak ordering):反身性、反对称性、传递性、不可比性的传递性
  • 不要用 return a.x == b.x && a.y == b.yoperator —— 这不满足严格弱序
  • 推荐写法:return std::tie(a.x, a.y)

为什么 set 不用哈希而用红黑树实现

因为 set 的核心契约是「有序 + 去重」,不是「快查」。红黑树天然支持 O(log n) 插入/删除/查找,且中序遍历即升序;而哈希表(如 unordered_set)虽平均 O(1),但不保证顺序,也无法直接支持 lower_boundupper_bound 等范围操作。

性能影响明显:如果你只需要去重、不关心顺序,unordered_set 更快;但一旦需要迭代有序、或频繁调用 lower_bound 查找前驱后继,set 是唯一合理选择。

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

  • set 迭代器是双向迭代器,可 ++/--;unordered_set 是前向迭代器,只能 ++
  • set::find 返回指向有序位置的迭代器;unordered_set::find 返回任意位置的迭代器
  • 内存占用:红黑树每个节点带颜色和指针,比哈希桶略高,但更稳定(无哈希冲突扩容抖动)

手动触发去重?没必要,但要注意 insert 返回值

set::insert 返回 std::pair,其中 bool 表示是否成功插入(true = 新元素,false = 已存在)。这不是“手动去重”,而是标准协议的一部分,用于判断是否发生实际变更。

容易踩的坑:有人误用 set::emplace_hint 并传错 hint,导致性能退化甚至逻辑错误;还有人把 set 当作临时去重容器,反复构造再清空,其实不如直接用 std::vector + std::sort + std::unique(尤其数据量小或只去重一次时)。

  • 大批量插入建议用范围构造:set s(v.begin(), v.end());,比循环 insert 快(内部优化为批量建树)
  • 若只是临时去重并转回 vector,且不需要中间有序,unordered_set + vector 构造更快
  • 别对 set 调用 std

    ::unique
    —— 它要求相邻重复,而 set 根本不会存重复

自定义类型去重失败的典型调试路径

set 明明该去重却没去,优先检查三件事:

  • 确认 MyClass 的比较函数是否被正确使用:在 set 模板参数里显式传入,或确保 operator 是 public 且非模板
  • 打印插入前后 s.size() 和遍历输出,验证是否真没去重,还是你误判了“相同”逻辑(比如浮点数直接比较)
  • std::is_sorted(s.begin(), s.end(), comp) 检查是否真有序——如果返回 false,说明比较函数违反严格弱序,这是根本原因

最隐蔽的问题:比较函数里用了未初始化成员、或依赖外部状态(如全局变量),导致行为不稳定。这种 bug 往往只在特定编译器或优化等级下暴露。


# ai  # c++  # 区别  # 内存占用  # 为什么  # red  # less  # sort  # 全局变量  # bool  # int  # 循环  # 指针  # 数据结构  # public  # operator  # 对象  # bug  # 自定义  # 迭代  # 红黑  # 遍历  # 更快  # 却没  # 没去  # 的是  # 这是  # 升序 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 微信公众帐号开发教程之图文消息全攻略  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?  利用python获取某年中每个月的第一天和最后一天  成都品牌网站制作公司,成都营业执照年报网上怎么办理?  JavaScript数据类型有哪些_如何准确判断一个变量的类型  Android中AutoCompleteTextView自动提示  php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】  如何快速搭建支持数据库操作的智能建站平台?  如何快速生成凡客建站的专业级图册?  Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程  中国移动官方网站首页入口 中国移动官网网页登录  js实现获取鼠标当前的位置  如何在IIS7中新建站点?详细步骤解析  Laravel如何实现密码重置功能_Laravel密码找回与重置流程  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  如何在搬瓦工VPS快速搭建网站?  在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?  Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】  node.js报错:Cannot find module 'ejs'的解决办法  企业网站制作这些问题要关注  动图在线制作网站有哪些,滑动动图图集怎么做?  宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程  网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?  网站制作价目表怎么做,珍爱网婚介费用多少?  Laravel PHP版本要求一览_Laravel各版本环境要求对照  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制  香港服务器WordPress建站指南:SEO优化与高效部署策略  laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法  Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言  如何快速打造个性化非模板自助建站?  php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】  如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程  如何在Ubuntu系统下快速搭建WordPress个人网站?  微信小程序 require机制详解及实例代码  Laravel如何使用withoutEvents方法临时禁用模型事件  SQL查询语句优化的实用方法总结  php 三元运算符实例详细介绍  微信推文制作网站有哪些,怎么做微信推文,急?  Laravel用户密码怎么加密_Laravel Hash门面使用教程  php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】  微信小程序 wx.uploadFile无法上传解决办法  微信小程序 HTTPS报错整理常见问题及解决方案  Laravel如何创建自定义中间件?(Middleware代码示例)  Laravel如何实现模型的全局作用域?(Global Scope示例)  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  ChatGPT 4.0官网入口地址 ChatGPT在线体验官网