我有两个排序的C ++ std :: vector没有重复(你可以称之为集合),我想知道它们是否相交。我不需要常见元素的向量。
我在boost“range”库中使用boost :: set_intersection算法在这个问题的最后编写了代码(http://www.boost.org/doc/libs/1_50_0/libs/range/doc/ HTML /范围/参考/算法/ set.html)。此代码避免构造公共元素集,但会扫描向量的所有元素。
是否有可能在不使用循环的情况下使用boost和C ++ STL改进我的函数“相交”?我想停止向量中的第一个共同元素,或者至少避免我的反击类。
增强范围库提供“包含”和“set_intersection”但不提供“相交”。这让我觉得“相交”是微不足道的,或者在其他地方提供,但我找不到它。
谢谢!
#include <vector>
#include <string>
#include <boost/assign/list_of.hpp>
#include <boost/function_output_iterator.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
template<typename T>
class counter
{
size_t * _n;
public:
counter(size_t * b) : _n(b) {}
void operator()(const T & x) const
{
++*_n;
}
};
bool intersects(const std::vector<std::string> & a, const std::vector<std::string> & b)
{
size_t found = 0;
boost::set_intersection(a, b, boost::make_function_output_iterator(counter<std::string>(&found)));
return found;
}
int main(int argc, char ** argv)
{
namespace ba = boost::assign;
using namespace std;
vector<string> a = ba::list_of(string("b"))(string("vv"))(string("h"));
vector<string> b = ba::list_of(string("z"))(string("h"))(string("aa"));
boost::erase(a, boost::unique<boost::return_found_end>(boost::sort(a)));
boost::erase(b, boost::unique<boost::return_found_end>(boost::sort(b)));
cout << "does " << (intersects(a, b) ? "" : "not ") << "intersect\n";
return 0;
}
答案 0 :(得分:3)
首先回答评论,boost的set_intersection将范围作为参数,与采用迭代器的STL相比。
除此之外,在算法和复杂性方面没有真正的区别。
据我所知,没有现成的库函数可以做你想做的事情,只测试两个序列是否唯一,如果不是则立即停止。
您还必须意识到,您将始终拥有&#34;最糟糕的情况&#34;当他们真的很独特时。
复杂度为O(N + M),尽管您也可以在其中一个集合上使用二进制搜索,这将使其成为O(N log M)或O(M log N),并且如果一个大于另一个这可能是一个很大的节省。 (例如,N = 1000000,M = 20,M log N仅约为400)
你可以减少&#34;取中位数为1,在另一个中找到它,并在不同的线程中比较子范围。
还有可怕的&#34;让你的仿函数在交叉点上被调用的解决方案,从而让你脱离循环。 (是的,那里有一个,即使它隐藏在算法中)。我们可以写自己的,虽然这是O(N + M)非常简单。我将使用4个迭代器来完成它:
template< typename Iter1, typename Iter2 >
bool intersects( Iter1 iter1, Iter1 iter1End, Iter2 iter2, Iter2 iter2End )
{
while( iter1 != iter1End && iter2 != iter2End )
{
if( *iter1 < *iter2 )
{
++iter1;
}
else if ( *iter2 < *iter1 )
{
++iter2;
}
else
return true;
}
return false;
}
// Predicate version where the compare version returns <0 >0 or 0
template< typename Iter1, typename Iter2, typename Comp >
bool intersects( Iter1 iter1, Iter1 iter1End, Iter2 iter2, Iter2 iter2End, Comp comp )
{
while( iter1 != iter1End && iter2 != iter2End )
{
int res = comp( *iter1, *iter2 );
if( res < 0 )
{
++iter1;
}
else if ( res > 0 )
{
++iter2;
}
else
return true;
}
return false;
}