Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么';std::merge和std::set_union之间的区别是什么?_C++_Merge - Fatal编程技术网

C++ 什么';std::merge和std::set_union之间的区别是什么?

C++ 什么';std::merge和std::set_union之间的区别是什么?,c++,merge,C++,Merge,问题很清楚,我的google-and-cplusplus.com/reference-fu让我失望。std::merge合并所有元素,但不消除重复项,而std::set\u union消除重复项。也就是说,后者应用了的操作规则。std::merge在输出中保留两个范围中的所有元素,第一个范围中的等效元素在第二个范围中的等效元素之前。当两个范围中都出现等效元素时,std::set_union仅从第一个范围中获取元素,否则每个元素按std::merge的顺序合并 参考文献:ISO/IEC 14882

问题很清楚,我的google-and-cplusplus.com/reference-fu让我失望。

std::merge
合并所有元素,但不消除重复项,而
std::set\u union
消除重复项。也就是说,后者应用了的操作规则。

std::merge
在输出中保留两个范围中的所有元素,第一个范围中的等效元素在第二个范围中的等效元素之前。当两个范围中都出现等效元素时,
std::set_union
仅从第一个范围中获取元素,否则每个元素按
std::merge
的顺序合并

参考文献:ISO/IEC 14882:2003 25.3.4[lib.alg.merge]和25.3.5.2[lib.set.union]。

将包含两个集合中仅存在一次的元素。将包含它们两次

例如,使用
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';
}

这是我在我发布到已接受答案的评论中建议的验证(即,如果一个元素出现在其中一个输入集中N次,它将出现在set_union的输出中N次-因此set_union不会以我们“自然”或“数学”预期的方式删除重复的等效项-但是,如果两个输入范围只包含一次公共项,则set_union将似乎删除du折叠的

#包括
#包括
#包括
#包括
使用名称空间std;

无效打印机(int i){cout添加到前面的答案中-注意
std::set_union
的复杂性是
std::merge
的两倍。实际上,这意味着
std::set_union
中的比较器可以在元素被取消引用后应用于该元素,而
std::merge
中的比较器永远不会是这种情况

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

std::vector<Foo> lhs, rhs;
但是现在假设
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

具有相同的复杂性,这听起来更像是交叉点,不是吗?@davka:我说的是在第二个范围中存在等价物的行为。我认为其他范围中没有等价物的所有元素都会被保留。我已经澄清了我的措辞。好的,在读了这句话之后nce 5次:)我明白你的意思。我把它理解为“只需要”…@davka:请仔细阅读,我说的“只需要”,我认为更清楚。我会尽力:)我认为你的新措辞更清楚。对我们许多人来说,英语是第二(或第N)位语言
std::merge
也可以处理排序范围并生成排序结果。@Charkes Bailey:谢谢,我没有检查std::merge,也不认为它会这样做。修改了我的答案。为了每个人的利益,也许是我太挑剔了,但上面的内容不够清晰,我不喜欢。阅读这个答案可能会让你相信duplicate由set_union()消除-它们是消除的,但不一定以您可能认为的方式。如果第一个范围多次包含等效元素,则该元素将在输出范围中出现相同的次数。这很容易验证:(很抱歉,stackoverflow仍然是新手,该验证无法在注释中显示为代码,因此我创建了一个包含详细信息的新答案)我同意这是一个非常不清楚的答案。这意味着集合\并集实际上是一个交集,而不是一个并集。@Emilie:正如我在问题中所说的,这并没有给我提供答案。为什么我只想用一个
std::set
…感谢我眼中最简洁明了的答案。
std::set_union(std::cbegin(lhs), std::cend(lhs),
               std::cbegin(rhs), std::cend(rhs),
               std::back_inserter(union));
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));
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));