std::set_intersection 可用于 std::multiset,但需用 std::inserter 向空 multiset 插入,结果保留 min(count₁,count₂) 个重复元素;误用 set 或普通指针会导致去重或崩溃。

std::set_intersection 为什么不能直接用在 std::multiset 上?
因为 std::set_intersection 要求输入范围是“已排序且去重”的,而 std::multiset 允许重复元素,它的“排序”是按值升序、但相同值可多次出现——这恰好符合 std::set_intersection 的底层要求(只要有序,不管是否唯一),所以它其实能用,只是行为和直觉不符:std::set_intersection 对每个相等值只保留 min(count₁, count₂) 个副本,而这正是 multiset 交集的正确定义。很多人误以为它“不支持 multiset”,其实是没传对迭代器或没选对输出容器。
- 必须用
std::inserter或std::back_inserter向目标std::multiset插入,不能用普通指针或数组 - 两个输入
std::multiset必须都已排序(它们天生就是,放心) - 输出容器也得是支持重复插入的,比如
std::multiset或std::vector;若用std::set,重复会被自动丢弃
正确调用 std::set_intersection 计算 multiset 交集
核心是把 std::set_intersection 的输出目标设为一个空的 std::multiset,并用 std::inserter 包装。它会自动调用 insert(),保留重复次数。
#include <algorithm>
#include <set>
#include <iterator>
std::multiset<int> a = {1, 2, 2, 3, 3, 3};
std::multiset<int> b = {2, 2, 2, 3, 4};
std::multiset<int> result;
std::set_intersection(a.begin(), a.end(),
b.begin(), b.end(),
std::inserter(result, result.end()));
// result == {2, 2, 3}
-
std::inserter(result, result.end())比std::back_inserter更稳妥:multiset 不保证 insert 位置,但inserter语义明确 - 如果想存到
std::vector里(避免红黑树开销),就用std::back_inserter(vec),结果仍是 {2,2,3},顺序也保持升序 - 别漏掉头文件:
<algorithm>和<iterator>缺一不可
手写循环实现:更可控,适合调试或定制逻辑
当需要跳过某些值、加条件过滤,或想确认计数逻辑时,手动双指针遍历最清晰。本质就是模拟 multiset 的归并交集:对每个相等值,取两者中较小的出现次数,然后插入那么多次。
std::multiset<int> a = {1, 2, 2, 3, 3, 3};
std::multiset<int> b = {2, 2, 2, 3, 4};
std::multiset<int> result;
auto it_a = a.begin(), it_b = b.begin();
while (it_a != a.end() && it_b != b.end()) {
if (*it_a == *it_b) {
int count_a = a.count(*it_a); // O(log n + k),k 是重复数
int count_b = b.count(*it_b); // 同上 —— 注意:频繁调用 count() 在大集合里很慢
int common_count = std::min(count_a, count_b);
result.insert(*it_a, common_count); // 插入 common_count 个副本
it_a = a.upper_bound(*it_a); // 跳过所有相同值
it_b = b.upper_bound(*it_b);
} else if (*it_a < *it_b) {
++it_a;
} else {
++it_b;
}
}
-
a.count(x)在内部遍历重复段,对高频重复数据性能差;生产环境建议改用std::distance+equal_range获取精确区间 -
a.upper_bound(x)直接跳到第一个 > x 的位置,比手动 ++ 更安全高效 - 这个版本更容易加日志、断点或修改交集定义(比如改成“至少出现两次才计入”)
常见错误:为什么结果为空或少了元素?
最常踩的坑不是算法错,而是容器类型或插入方式不对。
立即学习“C++免费学习笔记(深入)”;
- 用
std::set<int>接收结果 → 所有重复被合并成一个,交集变成 {2,3},不是 {2,2,3} - 输出用
std::copy或裸指针数组 → 编译失败或越界写入 - 传了
a.end()但忘了b.end(),或者反了顺序(a和b位置互换不影响结果,但写反容易引发混淆) - 在非 multiset 容器(如
std::vector)上调用count()→ 编译不过,因为std::vector::count不存在
交集的“保留所有副本”本质上是频次取 min,不是简单元素存在性判断;只要记住这点,选对容器和 inserter,基本不会出错。


















