是否可以使用`std :: set_intersection`来检查两个集合是否有任何共同的元素?

时间:2017-10-16 12:10:37

标签: c++ stl iterator set c++17

std::set_intersection允许我通过将元素输出到输出迭代器来检索两个std::set实例之间的所有共同元素。在我的特殊情况下,我只对检查两个集合是否有任何共同元素感兴趣。

我目前的解决方案是使用boost::function_output_iterator设置bool变量,如下所示:

bool b{false};
set_intersection(begin(s0), end(s0),
                 begin(s1), end(s1),
                 make_function_output_iterator([&](const auto&){ b = true; }));
return b;

不幸的是,如果找到匹配项,此解决方案不会提前返回:必须完全遍历(即没有提前返回/短路)

是否可以在早期返回时使用set_intersection我能想到的唯一解决方案是从function_output_iterator 函数对象中抛出异常,这是一个可怕的想法。

如果没有,标准库中还有其他可以帮助我的内容,还是我被迫重新实现set_intersection?奖金问题:set_intersection界面如果允许提前终止(即什么是标准库算法可能具有的#34;最通用"接口),将如何看待?

3 个答案:

答案 0 :(得分:9)

好吧,被“强迫”重新实现std::set_intersection并不是一件坏事。 &LT g取代;它只有大约五行代码:

template <class I1, class I2>
bool have_common_element(I1 first1, I1 last1, I2 first2, I2 last2) {
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2)
            ++first1;
        else if (*first2 < *first1)
            ++first2;
        else
            return true;
    }
    return false;
}

好的,超过5行。但无痛。

答案 1 :(得分:3)

这个简单的算法应该这样做:

特点:

  • 复杂度:最多K =最大(N,M)次迭代,其中N是距离(first1,last1),M是距离(first2,last2)
  • 短路
  • 适用于任何已排序的范围
  • 谓词可以替换

#include <set>
#include <ciso646>
#include <iostream>
#include <cassert>
#include <functional>

template<class I1, class I2, class Comp = std::less<> >
bool has_element_in_common(I1 first1, I1 last1, I2 first2, I2 last2, Comp&& comp = Comp())
{
    while (first1 != last1 and first2 != last2)
    {
        if (comp(*first1, *first2))
        {
            ++first1;
        }
        else if (comp(*first2, *first1))
        {
            ++first2;
        }
        else
        {
            return true;
        }
    }

    return false;
}


int main()
{
    auto s1 = std::set<int> { 1, 3, 5, 7, 9 };
    auto s2 = std::set<int> { 2, 3, 4, 6, 8 };

    assert(has_element_in_common(begin(s1), end(s1), begin(s2), end(s2)));

    auto s3 = std::set<int> { 2, 4, 6, 8 };

    assert(!has_element_in_common(begin(s1), end(s1), 
                                  begin(s3), end(s3)));

}

如果你想优化它以跳过多重集中的重复项,那么它需要做一些工作。

答案 2 :(得分:0)

你可以抛出异常,虽然异常开销很大......根据编程风格,你不应该像这样使用它:

bool find=false;
try{
set_intersection(begin(s0), end(s0),
                 begin(s1), end(s1),
                 make_function_output_iterator([&](const auto&){throw true;}));
}catch{
   find= true;
}