C++ multiset怎么用 C++允许重复元素的集合容器详解【应用】

3次阅读

multiset是允许重复元素的有序关联容器,而set不允许重复;二者均基于红黑树实现、自动升序、支持O(log n)操作,但multiset特有erase(key)删除所有匹配项、equal_range()获取重复元素区间。

C++ multiset怎么用 C++允许重复元素的集合容器详解【应用】

multiset 是什么,和 set 有什么根本区别

multisetc++ 标准库中基于红黑树实现的有序关联容器,它允许重复键值(即相同元素可多次插入),而 set 不允许。两者都自动维持元素升序排列、支持 O(log n) 插入/查找/删除,但底层行为差异直接影响使用逻辑:

  • multisetfind() 只返回一个匹配迭代器(不保证是第一个或最后一个)
  • count() 返回重复次数,equal_range() 才能拿到所有相同元素的区间
  • 迭代器不可修改所指元素(因为会破坏排序),但可修改其副本或用于 erase/insert

插入、遍历、删指定值的所有实例

插入和遍历和其他容器类似,但删除需特别注意“删一个”还是“删全部”:

  • insert(x) 总是成功,重复值照插不误
  • 遍历时用 for (const auto& v : ms) 得到升序序列,含重复
  • 删除单个匹配值:用 ms.erase(ms.find(x))(前提是 find() 不返回 end()
  • 删除所有匹配值:直接 ms.erase(x)(这是 multiset 特有的重载,set 没这个)
  • 删除某迭代器位置:ms.erase(it),只删一个
std::multiset ms = {1, 2, 2, 3, 3, 3}; ms.erase(3);          // 全部 3 被删,剩下 {1,2,2} ms.insert(2); // 现在是 {1,2,2,2},不是 {1,2,2,2,3}

如何安全获取所有重复元素的位置

不能依赖 find(),它只给一个;也不能用 lower_bound()/upper_bound() 自己算——容易越界或漏判。正确方式是统一用 equal_range()

  • 返回 std::pair,左闭右开区间
  • 若元素不存在,两个迭代器相等,都等于 end()
  • 区间内所有元素严格等于目标值,且已排序(当然,它们本来就是相等的)
auto range = ms.equal_range(2); for (auto it = range.first; it != range.second; ++it) {     std::cout << *it << " "; // 输出所有 2 }

性能与替代方案权衡:什么时候不该用 multiset

multiset 的树结构带来稳定对数复杂度,但常数较大,且不支持随机访问。以下场景要谨慎:

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

  • 只需计数不需要有序遍历:用 std::unordered_map 更快,内存也更省
  • 插入后只查总数、不遍历具体元素:mapunordered_map + operator[] 足够
  • 需频繁按位置取第 k 小(如 TopK):考虑 std::priority_queue 或带索引的平衡树(如 pb_ds tree)
  • 元素类型重载了 operator 但语义不稳定(比如浮点比较未处理精度):会导致插入错位或 find 失败

真正需要 multiset 的典型场景是:既要自动排序,又要保留重复,并且得逐个访问这些重复值(比如事件时间戳队列、带优先级的待处理任务池)。

重复元素的“存在性”和“数量”是两回事,multiset 解决的是前者+顺序,后者只是附带能力;别把它当计数器用。

text=ZqhQzanResources