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}
</int></int></int></iterator></set></algorithm>
-
std::inserter(result, result.end())比std::back_inserter更稳妥:multiset 不保证 insert 位置,但inserter语义明确 - 如果想存到
std::vector里(避免红黑树开销),就用std::back_inserter(vec),结果仍是 {2,2,3},顺序也保持升序 - 别漏掉头文件:
<algorithm></algorithm>和<iterator></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
<ul>
<li>
<code>a.count(x)</code> 在内部遍历重复段,对高频重复数据性能差;生产环境建议改用 <code>std::distance</code> + <code>equal_range</code> 获取精确区间</li>
<li>
<code>a.upper_bound(x)</code> 直接跳到第一个 > x 的位置,比手动 ++ 更安全高效</li>
<li>这个版本更容易加日志、断点或修改交集定义(比如改成“至少出现两次才计入”)</li>
</ul>
<h3>常见错误:为什么结果为空或少了元素?</h3>
<p>最常踩的坑不是算法错,而是容器类型或插入方式不对。</p>
<ul>
<li>用 <code>std::set<int></int></code> 接收结果 → 所有重复被合并成一个,交集变成 {2,3},不是 {2,2,3}</li>
<li>输出用 <code>std::copy</code> 或裸指针数组 → 编译失败或越界写入</li>
<li>传了 <code>a.end()</code> 但忘了 <code>b.end()</code>,或者反了顺序(<code>a</code> 和 <code>b</code> 位置互换不影响结果,但写反容易引发混淆)</li>
<li>在非 multiset 容器(如 <code>std::vector</code>)上调用 <code>count()</code> → 编译不过,因为 <code>std::vector::count</code> 不存在</li>
</ul>
<p>交集的“保留所有副本”本质上是频次取 min,不是简单元素存在性判断;只要记住这点,选对容器和 inserter,基本不会出错。</p></int></int></int>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











