set_intersection要求输入范围升序排列,因其仅执行归并扫描而非排序;若传入未排序容器将导致结果错误或遗漏交集元素。

set_intersection 为什么必须传入已排序的容器
set_intersection 不做排序,只做归并扫描。它假设两个输入范围都是升序排列的,内部用双指针逐个比对元素——如果传入未排序的 std::vector 或乱序 std::list,结果不可预测,甚至可能跳过合法交集元素。
常见错误现象:set_intersection 返回空结果,或只返回部分交集,而手动检查发现明明有重合元素。
- 使用前务必确保输入迭代器范围有序(可用
std::sort预处理) -
std::set和std::multiset的底层红黑树天然有序,可直接传其begin()/end() - 若需保留原始顺序但又要交集,先复制、排序、求交、再映射回原索引(额外开销)
如何正确调用 set_intersection 并保存结果
它不分配内存,只把结果写入你提供的输出迭代器。最常用的是配合 std::back_inserter 写入 std::vector:
std::vectora = {1, 2, 4, 5}; std::vector b = {2, 3, 4, 6}; std::vector result; std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(result)); // result == {2, 4}
- 输出容器必须可增长(
std::vector、std::list),不能是固定大小数组 - 若提前知道最大交集大小,也可用
result.resize(std::min(a.size(), b.size()))+ 普通指针迭代器,再用result.erase(...)截断 - 注意:输出迭代器类型必须支持赋值(
*it++ = value),std::ostream_iterator也合法,但仅用于打印
处理重复元素:set_intersection vs multiset_intersection
set_intersection 按“数学集合”语义处理:每个值最多出现一次,即使输入含重复(如 {1,1,2} 和 {1,2,2}),结果仍是 {1,2}。
立即学习“C++免费学习笔记(深入)”;
- 要保留重复次数(即“多重集合交集”),得用
std::set_intersection配合std::multiset——前提是输入本身是multiset且已排序(它们天然满足) - 或者手写逻辑:用
std::count统计较小集合中某值出现次数,取 min 后插入对应次数 - 性能提示:对
multiset调用set_intersection仍只产生去重结果;真要多重交集,必须自己实现或用std::remove_copy_if等组合
替代方案:不用算法库,直接用 set/multiset 的成员函数
如果你操作的是 std::set 或 std::multiset,不必非用泛型算法。更简洁安全的方式是遍历较小集合,用 find 查询:
std::seta = {1, 2, 4, 5}; std::set b = {2, 3, 4, 6}; std::set result; for (const auto& x : a) { if (b.find(x) != b.end()) result.insert(x); }
- 代码更直观,无需担心排序或迭代器有效性
- 时间复杂度为 O(n log m),略慢于
set_intersection的 O(n + m),但对中小规模数据差异不明显 - 优势在于可随时加入条件过滤(比如只取偶数交集),而泛型算法难以嵌入逻辑
真正容易被忽略的是:set_intersection 的输入范围必须严格升序,连相等元素的相对位置都影响结果;而 set::find 方式完全规避了这个约束,也更贴近日常调试直觉。










