std :: merge和std :: set_union有什么区别?

时间:2011-03-06 16:37:56

标签: c++ merge

问题很明显,我的google-和cplusplus.com/reference-fu让我失望。

5 个答案:

答案 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会消除重复项。也就是说,后者适用unionset theory操作规则。

答案 4 :(得分:1)

要添加到之前的答案 - 请注意std::set_union的复杂性是std::merge的两倍。在实践中,这意味着std::set_union中的比较器可以在被取消引用后应用于元素,而std::merge则不会出现这种情况。

为什么这很重要?考虑类似的事情:

std::vector<Foo> lhs, rhs;

您希望生成lhsrhs

的联合
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具有相同的复杂性。