multiset与set的关键区别是multiset允许重复元素而set不允许;两者均基于红黑树实现自动升序排序,但multiset的insert()接受重复值,需用count()统计次数,erase(key)删除所有匹配元素,自定义比较器必须满足严格弱序。

multiset 和 set 有什么关键区别?
核心就一点:multiset 允许重复元素,set 不允许。两者底层都是红黑树,自动排序(升序),但 multiset 的 insert() 不会拒绝相同值——它只是多插一个节点。
这意味着你不能用 operator[](multiset 根本没重载这个),也不能靠 find() 判断“是否存在”来代替“计数”,因为 find() 只返回任意一个迭代器,不反映重复次数。
常见误判场景:想查某个值出现几次,却只调一次 find() 就以为“找到了=存在=1次”,实际可能有 5 次。
怎么插入、遍历和统计重复元素?
插入直接用 insert(),支持单个值、迭代器区间、初始化列表;遍历时用普通迭代器即可,重复元素相邻排列(因有序);统计某值出现次数必须用 count(),不是 size() 或手写循环。
立即学习“C++免费学习笔记(深入)”;
-
multiset—— 合法,含三个 2s = {1, 2, 2, 2, 3}; -
s.insert(2);—— 插入后共四个 2 -
auto range = s.equal_range(2);—— 返回pair,左闭右开区间,等价于count()但能遍历所有 2 -
s.count(2)返回4,s.find(2)只返回第一个 2 的迭代器
删除元素时要注意什么?
multiset::erase() 有三个重载,行为差异极大:
-
erase(iterator):删单个节点(传入的迭代器所指的那个) -
erase(const key_type&):删掉所有等于该 key 的元素(返回删除个数) -
erase(iterator first, iterator last):删区间,注意是左闭右开
典型陷阱:s.erase(2) 看似像 find(),实则清空所有 2;若只想删一个,必须先 find() 拿到迭代器再传给 erase(iterator)。
另外,erase() 后原迭代器失效(除被删的那个),尤其用 equal_range 得到的迭代器,删完不能再用。
multiset 能否自定义比较规则?
可以,和 set 一样通过模板参数传入比较器,但要注意:自定义比较器必须满足「等价性」,即 comp(a,b)==false && comp(b,a)==false 才算相等。否则 count()、equal_range() 行为不可靠。
例如按字符串长度排序:
struct CmpByLen {
bool operator()(const string& a, const string& b) const {
return a.length() < b.length(); // ✅ 正确
// return a.length() <= b.length(); // ❌ 错!不满足严格弱序
}
};
multiset s;
如果比较逻辑写错,multiset 可能插入失败、遍历乱序,甚至触发未定义行为——这点比 vector 严苛得多,容易被忽略。










