简体   繁体   中英

Check whether two elements have a common element in C++

I want the function to return true when there is any element matching between two vectors,

Note : My vectors are not sorted Following is my source code,

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;
}

This is working fine when the size of vector B is less than the size of vector A , but returning false even there is match when size of vector B is greater than size of vector A .

The problem with posted code is that you should not use std::binary_search when the vector is not sorted. The behaviour is defined only for sorted range.

If the input vectors are not sorted then you can use find_first_of to check for existence of first common element found.

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();
}

Complexity of find_first_of is up to linear in inVectorA.size()*inVectorB.size() ; it compares elements until a match is found.

If you want to fix your original algorithm then you can make a copy of one of vectors and std::sort it, then std::binary_search works with it.

In actual programs that do lot of such matching between containers the containers are usually kept sorted. Then the complexity of search is up to linear in inVectorA.size()+inVectorB.size() .

std::find_first_of is more efficient than to sort both ranges and then to search for match when both ranges are rather short or second range is shorter than binary logarithm of length of first range.

You can use a well-defined algorithm called as std::set_intersection to check if there is any common element between these vectors.

Pre-condition :- Both vectors be sorted.

Here is an implementation which uses sorted vectors, doesn't construct a new container, and which has only linear complexity (more detailed: 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

You could do something like the following. Iterate over the first vector. For each element, use std::find to see if it exists in the other vector. If you find it, they have at least one common element so return true. Otherwise, move to the next element of the first vector and repeat this process. If you make it all the way through the first vector without finding a common element, there is no intersection so return 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;
}

Usage of std::set_intersection is one option. Since the vector's elements are sorted, the code can be simplified to this:

#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()
}

The drawback is that a temporary vector is being created while the set_intersection is being executed (but maybe in the future, this can be considered a "feature" if you want to know what elements are common).

Your code uses std::binary_search , whose pre-condition is that (From http://en.cppreference.com/w/cpp/algorithm/binary_search ):

For std::binary_search to succeed, the range [first, last) must be at least partially ordered, ie it must satisfy all of the following requirements:

  • partitioned with respect to element < value or comp(element, value)
    • partitioned with respect to !(value < element) or !comp(value, element)
    • for all elements, if element < value or comp(element, value) is true then !(value < element) or !comp(value, element) is also true

A fully-sorted range meets these criteria, as does a range resulting from a call to std::partition .

The sample data you used for testing (as posted at http://ideone.com/XCYdM8 ) do not meet that requirement. Instead of using:

   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);

if you use a sorted vector like below

   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);

your function will work just fine.

PS The you have designed your code, if the longer std::vector is sorted, the function will work fine.

PS2 Another option is to sort the longer std::vector before calling the function.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM