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;
}
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
orcomp(element, value)
- partitioned with respect to
!(value < element)
or!comp(value, element)
- for all elements, if
element < value
orcomp(element, value)
istrue
then!(value < element)
or!comp(value, element)
is alsotrue
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.