7

我想知道标准库中是否有任何工具可以同时计算两个排序范围之间的集合交集和集合差。带有以下签名的东西:

template <class Input1, class Input2, 
          class Output1, class Output2, class Output3>
Output3 decompose_sets (Input1 first1, Input1 last1,
                        Input2 first2, Input2 last2,
                        Output1 result1, Output2 result2,
                        Output3 result3 );

这样在调用之后decompose setsresult1包含所有[first1,last1)不在其中的元素[first2,last2),包含所有不在其中result2的元素,并包含所有在和中共有的元素。[first2,last2)[first1,last1)result3[first1,last1)[first2,last2)

set_difference和的示例实现set_intersection来自 cplusplus.com 的示例实现似乎可以帮助我创建一个只执行一次扫描而不是三个扫描的高效实现。但是,如果它在标准库中,我不想重新发明轮子。

示例,应要求:

给定两个集合 a={0, 1, 2, 3, 4} 和 b={2, 4, 5, 6} 那么我想构建以下三个集合:

  • only_a = {0,1,3}
  • only_b = {5,6}
  • 常见 = {2,4}
4

3 回答 3

3

没有标准库算法可以在一次扫描中完成,但它很容易编写。以下看起来是正确的,并且输出在 ideone.com 上有意义

template <class Input1, class Input2,
            class Output1, class Output2, class Output3>
Output3 decompose_sets(Input1 first1, Input1 last1,
                    Input2 first2, Input2 last2,
                    Output1 result1, Output2 result2,
                    Output3 result3)
{
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            *result1++ = *first1++;
        } else if (*first2 < *first1) {
            *result2++ = *first2++;
        } else {
            *result3++ = *first1++;
            ++first2; // skip common value in set2
        }
    }
    std::copy(first1, last1, result1);
    std::copy(first2, last2, result2);
    return result3;
}
于 2013-08-10T18:02:38.773 回答
1

STL 中没有这样的功能,但是有set_symmetric_difference()构造一个排序的序列,其中包含第一个序列中存在但第二个序列中不存在的元素,并且第二个序列中存在的那些元素不存在于第一个序列中。

于 2013-08-10T17:26:35.177 回答
0

这是另一种选择,它使用回调以获得最大的灵活性。

template <class Input1, class Input2
            , class FuncAdd, class FuncRm, class FuncSame, class Comp>
void set_difference_adv(Input1 firstOld, Input1 lastOld
                        ,Input2 firstNew, Input2 lastNew
                        ,FuncAdd onadded, FuncRm onremoved, FuncSame onsame, Comp comp)
{
  while (firstOld != lastOld && firstNew != lastNew) {

    if (comp(*firstOld, *firstNew)) {
      onremoved(*firstOld++);
    } else if (comp(*firstNew, *firstOld)) {
      onadded(*firstNew++);
    } else {
      onsame(*firstOld++, *firstNew++);
    }
  }

  std::for_each(firstOld, lastOld, onremoved);
  std::for_each(firstNew, lastNew, onadded);
}

这具有以下优点:

  • 输出列表现在是可选的
  • 输出可以是不同的类型(转换)
  • 常见的项目可以进一步串联处理(附加比较)

“现实世界”示例:

int main()
{
  using File = std::pair<std::string, int>;

  std::vector<File> files1{{"file1", 12}, {"file3", 8}, {"file4", 2}, {"file5", 10}};
  std::vector<File> files2{{"file1", 12}, {"file2", 5}, {"file3", 8}, {"file4", 33}};

  const auto less = [](const auto& o, const auto& n) { return o.first < n.first; };

  std::vector<std::string> addedNames;
  std::vector<File> changedFiles;

  set_difference_adv(std::cbegin(files1), std::cend(files1)
                     ,std::cbegin(files2), std::cend(files2)
                     , [&addedNames](const auto& val){ addedNames.push_back(val.first); } //< added (transform)
                     , [](const auto& val) {} //< removed (ignore)
                     , [&changedFiles](const auto& o, const auto& n){ if(n.second > o.second) changedFiles.push_back(n); } //< "same" (further compare)
                     , less
                     );  
}
于 2017-01-16T13:20:50.150 回答