问题很明确,我的 Google 和 cplusplus.com/reference 没有帮助到我。
std::set_union
会包含那些在两个集合中都出现一次的元素,std::merge
会将它们包含两次。
例如,对于 A = {1, 2, 5}; B = {2, 3, 4}
:
C = {1, 2, 3, 4, 5}
D = {1, 2, 2, 3, 4, 5}
两者都适用于排序范围,并返回一个已排序的结果。
简单示例:
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
int main()
{
std::set<int> A = {1, 2, 5};
std::set<int> B = {2, 3, 4};
std::vector<int> out;
std::set_union(std::begin(A), std::end(A), std::begin(B), std::end(B),
std::back_inserter(out));
for (auto i : out)
{
std::cout << i << " ";
}
std::cout << '\n';
out.clear();
std::merge(std::begin(A), std::end(A), std::begin(B), std::end(B),
std::back_inserter(out));
for (auto i : out)
{
std::cout << i << " ";
}
std::cout << '\n';
}
输出:
1 2 3 4 5
1 2 2 3 4 5
std::merge
也适用于已排序的范围,并且生成一个已排序的结果。 - CB Baileystd::merge
函数会保留两个范围中的所有元素,第一个范围中等价的元素排在第二个范围中等价元素之前。如果两个范围中都有等价元素,则std::set_union
函数只选择第一个范围中的元素,否则每个元素都按顺序合并,与std::merge
相同。
参考文献:ISO/IEC 14882:2003 25.3.4 [lib.alg.merge] 和 25.3.5.2 [lib.set.union]。
这是我在已接受答案的评论中建议的验证(即,如果一个元素在其中一个输入集中出现N次,则它将在set_union的输出中出现N次 - 因此,set_union不会以我们“自然”或“数学”的方式删除重复的等效项 - 但是,如果两个输入范围仅包含一个共同项,则set_union将“看起来”删除重复项)
#include <vector>
#include <algorithm>
#include <iostream>
#include <cassert>
using namespace std;
void printer(int i) { cout << i << ", "; }
int main() {
int mynumbers1[] = { 0, 1, 2, 3, 3, 4 }; // this is sorted, 3 is dupe
int mynumbers2[] = { 5 }; // this is sorted
vector<int> union_result(10);
set_union(mynumbers1, mynumbers1 + sizeof(mynumbers1)/sizeof(int),
mynumbers2, mynumbers2 + sizeof(mynumbers2)/sizeof(int),
union_result.begin());
for_each(union_result.begin(), union_result.end(), printer);
return 0;
}
std::set_union
的复杂度是 std::merge
的两倍。在实践中,这意味着 std::set_union
中的比较器可能会在解引用后应用于元素,而对于 std::merge
,则从不出现这种情况。std::vector<Foo> lhs, rhs;
你想要生成lhs
和rhs
的并集:
std::set_union(std::cbegin(lhs), std::cend(lhs),
std::cbegin(rhs), std::cend(rhs),
std::back_inserter(union));
但是现在假设Foo
不可复制,或者复制非常昂贵而且您不需要原件。您可以考虑使用:
std::set_union(std::make_move_iterator(std::begin(lhs)),
std::make_move_iterator(std::end(lhs)),
std::make_move_iterator(std::begin(rhs)),
std::make_move_iterator(std::end(rhs)),
std::back_inserter(union));
Foo
!因此正确的解决方案是:std::merge(std::make_move_iterator(std::begin(lhs)),
std::make_move_iterator(std::end(lhs)),
std::make_move_iterator(std::begin(rhs)),
std::make_move_iterator(std::end(rhs)),
std::back_inserter(union));
union.erase(std::unique(std::begin(union), std::end(union), std::end(union));
这与 std::set_union
具有相同的复杂度。