在 C++ 中检查两个元素是不是有共同的元素

Posted

技术标签:

【中文标题】在 C++ 中检查两个元素是不是有共同的元素【英文标题】:Check whether two elements have a common element in C++在 C++ 中检查两个元素是否有共同的元素 【发布时间】:2014-11-25 16:16:13 【问题描述】:

我希望函数在两个向量之间有任何元素匹配时返回 true,

Note : My vectors are not sorted 以下是我的源代码,

bool CheckCommon( std::vector< long > &inVectorA, std::vector< long > &inVectorB )

    std::vector< long > *lower, *higher;

    size_t sizeL = 0, sizeH = 0;

    if( inVectorA.size() > inVectorB.size() )
    
        lower = &inVectorA;
        sizeL = inVectorA.size();
        higher = &inVectorB;
        sizeH = inVectorB.size();
    
    else
    
        lower = &inVectorB;
        sizeL = inVectorB.size();
        higher = &inVectorA;
        sizeH = inVectorA.size();
    

    size_t indexL = 0, indexH = 0;

    for( ; indexH < sizeH; indexH++ )
    
        bool exists = std::binary_search( lower->begin(), lower->end(), higher->at(indexH) );

        if( exists == true )
            return true;
        else
            continue;
    
    return false;

当向量 B 的大小小于向量 A 的大小时,这可以正常工作,但是当向量 B 的大小大于向量 A 的大小时,即使存在匹配也会返回 false。

【问题讨论】:

我们可以假设向量是排序的吗?如果是这样,std::set_intersection 可能是您应该尝试的。 @PaulMcKenzie 我是的,我看到了一个 std::binary_search 在不回答 OP 问题的情况下将不同的建议视为答案,这很奇怪。你看到 OP 的代码有什么问题吗?我还没看到呢。 @RSahu 这就是答案...选择已经定义的算法...否则为什么还要使用向量。 请发布您的示例数据。您的代码适用于我测试它的示例数据。请参阅ideone.com/MguVjk。 【参考方案1】:

发布代码的问题是当向量没有排序时你不应该使用std::binary_search。该行为仅针对排序范围定义。

如果输入向量未排序,则可以使用find_first_of 检查找到的第一个公共元素是否存在。

bool CheckCommon(std::vector<long> const& inVectorA, std::vector<long> const& nVectorB)

    return std::find_first_of (inVectorA.begin(), inVectorA.end(),
                               nVectorB.begin(), nVectorB.end()) != inVectorA.end();

find_first_of 的复杂度在inVectorA.size()*inVectorB.size() 中是线性的;它会比较元素直到找到匹配项。

如果你想修复你的原始算法,那么你可以复制一个向量并 std::sort 它,然后 std::binary_search 使用它。

在容器之间进行大量此类匹配的实际程序中,容器通常保持排序。那么搜索的复杂度在inVectorA.size()+inVectorB.size()中是线性的。

std::find_first_of 比对两个范围进行排序然后在两个范围都相当短或第二个范围比第一个范围长度的二进制对数短时搜索匹配更有效。

【讨论】:

它有效,请您告诉它的复杂性。【参考方案2】:

您可以使用称为std::set_intersection 的定义明确的算法来检查这些向量之间是否有任何共同元素。

前提条件:- 两个向量都被排序。

【讨论】:

【参考方案3】:

这是一个使用排序向量的实现,不构造新容器,并且只有线性复杂度(更详细:O(container1.size()+ container2.size()):

template< class ForwardIt1, class ForwardIt2 >
bool has_common_elements( ForwardIt1 first, ForwardIt1 last, ForwardIt2 s_first, ForwardIt2 s_last )

    auto it=first;
    auto s_it=s_first;
    while(it<last && s_it<s_last)
    
        if(*it==*s_it)
        
            return true;
        

        *it<*s_it ? ++it : ++s_it;  //increase the smaller of both
    
    return false;

DEMO

【讨论】:

我的向量未排序 当 first 等于 last 或 s_first 等于 s_last (IOW 其中一个序列为空)时,它会崩溃。 @Noname:没问题,排序。正如 ÖöTiib 所提到的,您将得到 O(size1+size2) + O(size1*log(size1)) + O(size2*log(size2))(比较 + 两次排序)而不是 O(size1*size2)。这可能是一个巨大的差异。 @davidhigh 目前的复杂度只有 O(smallVecSize * log(vigVecSize) 是否大于 O(smallVecSize + bigVecSize) ? 对于中等大小(例如,大约高达 10000),您可以放心地忘记对数因子。隐藏在O 中的常量前置因子通常更为重要。我建议你忘记渐近缩放,只做一些测试。【参考方案4】:

您可以执行以下操作。迭代第一个向量。对于每个元素,使用std::find 来查看它是否存在于另一个向量中。如果你找到它,它们至少有一个共同元素,所以返回 true。否则,移动到第一个向量的下一个元素并重复此过程。如果一直通过第一个向量而没有找到公共元素,则没有交集,因此返回 false。

bool CheckCommon(std::vector<long> const& inVectorA, std::vector<long> const& nVectorB)

    for (auto const& num : inVectorA)
    
        auto it = std::find(begin(nVectorB), end(nVectorB), num);
        if (it != end(nVectorB))
        
            return true;
        
    
    return false;

【讨论】:

@ravi 最坏的情况是O(N^2),但是如果它找到一个共同的元素,就会有短路行为,所以会更快。【参考方案5】:

使用std::set_intersection 是一种选择。由于向量的元素是排序的,代码可以简化为:

#include <algorithm>
#include <iterator>

bool CheckCommon( const std::vector< long > &inVectorA, const std::vector< long > &inVectorB )

    std::vector< long > temp;
    std::set_intersection(inVectorA.begin(), inVectorA.end(), 
                          inVectorB.begin(), inVectorB.end(),
                          std::back_inserter(temp));
    return !temp.empty()

缺点是在执行set_intersection 时会创建一个临时向量(但也许在将来,如果您想知道哪些元素是常见的,这可以被视为“功能”)。

【讨论】:

【参考方案6】:

您的代码使用std::binary_search,其前提是(来自http://en.cppreference.com/w/cpp/algorithm/binary_search):

要使std::binary_search 成功,[first, last) 范围必须至少部分排序,即它必须满足以下所有要求:

根据element &lt; valuecomp(element, value) 进行分区 根据!(value &lt; element)!comp(value, element) 进行分区 对于所有元素,如果element &lt; valuecomp(element, value)true,那么!(value &lt; element)!comp(value, element) 也是true

完全排序的范围符合这些条件,调用std::partition 产生的范围也是如此。

您用于测试的示例数据(发布于http://ideone.com/XCYdM8)不符合该要求。而不是使用:

   vectorB.push_back(11116);
   vectorB.push_back(11118);
   vectorB.push_back(11112);
   vectorB.push_back(11120);
   vectorB.push_back(11190);
   vectorB.push_back(11640);
   vectorB.push_back(11740);

如果您使用如下所示的排序向量

   vectorB.push_back(11112);
   vectorB.push_back(11116);
   vectorB.push_back(11118);
   vectorB.push_back(11120);
   vectorB.push_back(11190);
   vectorB.push_back(11640);
   vectorB.push_back(11740);

你的函数可以正常工作。

PS你已经设计好了你的代码,如果对较长的std::vector进行排序,函数就可以正常工作。

PS2 另一种选择是在调用函数之前对较长的std::vector 进行排序。

std::sort(B.begin(), B.end());

【讨论】:

以上是关于在 C++ 中检查两个元素是不是有共同的元素的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中检查向量的所有元素是不是相等

如何检查向量的所有元素是不是在 Eigen c++ 中的另一个向量中?

检查元素是不是在两个向量中的最快方法

检查元素是不是在列表中(包含)

python - 如何在python中使用IF语句检查两个列表的元素是不是相等?

C ++:检查向量中的元素是不是大于另一个具有相同索引的元素的有效方法?