在C++中求两个集合交集的标准方法如下:
std::set<int> set_1; // With some elements
std::set<int> set_2; // With some other elements
std::set<int> the_intersection; // Destination of intersect
std::set_intersection(set_1.begin(), set_1.end(), set_2.begin(), set_2.end(), std::inserter(the_intersection, the_intersection.end()));
我应该怎么做一个就地集合交集呢?也就是说,我想让set_1得到set_intersection调用的结果,显然,我可以只做一个set_1.swap(the_intersection)
,但是这比就地交集效率低很多。
3条答案
按热度按时间e4yzc0pl1#
我想我明白了:
有人看到问题了吗?两个集合的大小似乎是O(n)。根据cplusplus.com,std::set erase(position)是摊余常数,而erase(first,last)是O(log n)。
oyt4ldly2#
你可以很容易地遍历
set_1
,检查每个元素,看看它是否存在于set_2
中,如果不存在,就擦除它。因为集合是排序的,你可以在线性时间内比较它们,使用迭代器擦除一个元素就是amortized constant time。我不指望它比你开始时更有效,如果你在乎的话,基准测试是明智的。t1qtbnec3#
它没有直接回答这个问题,但也许有人觉得这很有帮助。
在
std::vector
的情况下,使用set_1.begin()
作为输出迭代器的标准算法是不安全的(见下文),而clang/gcc/microsoft实现可以工作。注意,set_2
* 可以是任何东西 *,不仅仅是std::vector
。更新:
感谢@基思,他发现C++标准(25.4.5.3)需要下一个:
结果范围不得与原始范围重叠
所以我最初的建议是错误的,但是在主要的STL实现中是可行的解决方案。如果你想安全起见,不想额外的分配,那么把你选择的实现复制到你的代码库中,用它代替
std::set_intersection
。我真的不明白这样限制的原因,如果你知道答案,请评论。