std::set_union求有序序列的并集而非std::set容器并集,仅处理已排序迭代器范围,需手动管理内存、保证输入有序、预留输出空间或用back_inserter。

std::set_union 求的是“有序序列的并集”,不是 std::set 容器的并集
很多人搜 std::set_union 是想合并两个 std::set,但这个函数和 std::set 类型无关——它只处理**已排序的迭代器范围**(比如两个 std::vector 或 std::array),输出也是按序排列的“去重并集”。如果你直接传两个 std::set 的 begin()/end(),语法上可行,但结果仍是普通迭代器操作,不改变原容器。
常见错误现象:std::set_union 返回一个迭代器,但如果你没提前分配足够空间或用插入迭代器,会触发未定义行为(比如写越界、静默截断)。
- 必须保证输入区间已升序排列(默认比较逻辑),否则结果不可靠
- 输出目标必须预留足够空间,或使用
std::back_inserter - 它不自动去重跨区间重复元素:若同一值在 A 和 B 中都出现,结果里只保留一个
正确调用 std::set_union 的三步实操
以两个 std::vector 为例,这是最常用也最不容易出错的场景:
#include <algorithm>
#include <vector>
#include <iterator>
<p>std::vector<int> a = {1, 2, 4, 6};
std::vector<int> b = {2, 3, 4, 5, 7};</p><p>std::vector<int> out;
out.reserve(a.size() + b.size()); // 预分配避免多次 realloc</p><p>std::set_union(a.begin(), a.end(),
b.begin(), b.end(),
std::back_inserter(out));
// out == {1,2,3,4,5,6,7}
- 输入必须是
[first1, last1)和[first2, last2)形式,不能漏掉end() - 第 5 个参数是输出迭代器,
std::back_inserter(out)最安全;用out.begin()前必须确保out.size() >= expected_size - 如果自定义类型,需传入第 6 个参数:比较函数,如
std::greater<int>{}(此时输入也得是降序)
想合并两个 std::set?别硬套 std::set_union
直接用 std::set 自带方法更自然、更高效:
立即学习“C++免费学习笔记(深入)”;
std::set<int> s1 = {1, 2, 4};
std::set<int> s2 = {2, 3, 4, 5};
<p>// 方法一:insert 批量插入(推荐)
s1.insert(s2.begin(), s2.end()); // s1 变成 {1,2,3,4,5}</p><p>// 方法二:遍历插入(等价,但显式)
for (const auto& x : s2) s1.insert(x);
-
std::set::insert对已存在元素无副作用,天然去重 - 时间复杂度是 O(m log(n+m)),比先转 vector 再
set_union再重建 set 更轻量 - 如果只是临时求并集且后续还要排序访问,才考虑转成 vector 后用
std::set_union
容易被忽略的细节:输出区间的长度不确定
std::set_union 不返回新容器,也不告诉你写了多少元素——它只返回**输出迭代器的终值**。这意味着:
- 用
std::back_inserter时,out.size()就是并集大小,无需额外计算 - 如果用预分配的 vector +
out.begin(),必须保存返回值来算长度:auto end_it = std::set_union(...); size_t len = end_it - out.begin(); - 没有“并集大小上限”公式:最大是
a.size() + b.size(),最小是std::max(a.size(), b.size()),实际取决于重复元素数量
真正麻烦的从来不是调用语法,而是记不住它不负责内存管理、不校验输入顺序、也不提供结果长度——这些全得你兜底。


















