问题很明显,我的google-和cplusplus.com/reference-fu让我失望。
答案 0 :(得分:13)
set_union将只包含两个集合中存在的元素。合并将包含它们两次。
两者都可以处理已排序的范围,并返回已排序的结果。
答案 1 :(得分:5)
std::merge
保留两个范围内的所有元素,来自输出中第二个范围的等效元素之前的第一个范围的等效元素。如果两个范围中出现等效元素,则std::set_union
仅获取第一个范围中的元素,否则每个元素将按照std::merge
的顺序合并。
参考文献:ISO / IEC 14882:2003 25.3.4 [lib.alg.merge]和25.3.5.2 [lib.set.union]。
答案 2 :(得分:2)
这是我在发布到已接受答案的评论中建议的验证(即,如果一个元素出现在其中一个输入集中N次,它将在set_union的输出中出现N次 - 所以set_union会 not 以“自然”或“数学”期望的方式删除重复的等效项目 - 但是,如果两个输入范围仅包含一个公共项目,则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;
}
这将打印:0,1,2,3,3,4,5,0,0,0,
答案 3 :(得分:1)
std::merge
合并所有元素,而不会消除重复项,而std::set_union
会消除重复项。也就是说,后者适用union的set theory操作规则。
答案 4 :(得分:1)
要添加到之前的答案 - 请注意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
具有相同的复杂性。