multiset底层是红黑树,自动排序、允许重复、不支持下标访问,所有操作o(log n);insert()只返回iterator因插入必成功;删全部用erase(key),删一个需先find再erase;equal_range是处理重复元素的核心工具。

multiset 不是“带重复的 set”那么简单——它底层是红黑树,元素自动排序、允许重复、不支持下标访问,且所有操作复杂度都是 O(log n)。用错场景(比如想靠它随机查某个重复值的位置),反而比 vector 还慢。
为什么 insert() 返回值和 set 不同?
multiset::insert() 只返回一个 iterator,不像 set::insert() 那样返回 pair<iterator bool></iterator>。因为 multiset 允许重复,插入必然成功,bool 标志没意义。
- 想确认是否真的新增了节点?不能靠返回值,得用
count()或前后迭代器比较 - 插入后要立即使用该位置的迭代器?记住它可能指向任意一个相同值的副本(红黑树不保证相同键的插入顺序)
- 批量插入用
insert(first, last)或初始化列表,性能优于单次循环调用insert()
如何安全地删除指定值的所有副本?别只用 erase(key)
multiset::erase(const key_type& k) 会删掉所有等于 k 的元素,并返回删除个数——这和 map 的行为一致,但容易误以为它只删一个(像 list::erase(iterator))。
- 只想删一个?必须先
find()拿到一个迭代器,再传给erase(iterator) - 删完要继续遍历?别用保存的
iterator,它已失效;改用erase()的返回值(C++11 起返回下一个有效迭代器) - 用
count(k) == 0判断是否存在?可以,但比find() != end()多一次对数查找,不推荐
equal_range() 是处理重复元素的核心工具
当你需要遍历、修改或统计某值的所有实例时,equal_range(key) 返回一对迭代器:[first, last),精确圈出所有相等元素的连续区间——这是 multiset 区别于其他容器的关键能力。
- 返回类型是
std::pair<iterator iterator></iterator>,不是std::pair<const_iterator const_iterator></const_iterator>(即使容器是 const,你仍可修改元素值,只要不破坏排序) - 区间内元素严格按插入逻辑排序?不。红黑树只保证整体有序,相同键之间无序,
equal_range返回的顺序取决于内部节点结构 - 配合
for (auto it = range.first; it != range.second; ++it)使用最安全;避免手写while循环漏判边界
真正难的不是语法,而是想清楚:你要的是“存在性判断”“单次操作”还是“范围批量处理”。选错接口,multiset 就从利器变成累赘——尤其在高频增删+需定位重复项的场景里,equal_range 和迭代器失效规则,一个疏忽就导致未定义行为。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











