While looking over some code I found loopy and algorithmically slow implementation of std::set_difference :
for(int i = 0; i < a.size(); i++)
{
iter = std::find(b.begin(),b.end(),a[i]);
if(iter != b.end())
{
b.erase(iter);
}
}
It can be easily replaced with sort(vectors are not sorted) + set_difference, but that requires allocation of new memory(see my recent Q Can output of set difference be stored in first input? why it cant be done "inplace").
So my solution would be something like:
sort(a.begin(), a.end());
for(size_t i = 0; i < b.size(); i++)
{
if (binary_search(a.begin(), a.end(), b[i]))
{
swap(b[i], b[b.size()-1]); //remove current element by swapping with last
b.pop_back(); // and removing new last by shrinking
}
}
can it be done more elegantly?
elegant is subjective so within scope of this Q is defined as clearer code(ideally something from STL algorithms but I think it cant be done) but with no memory allocation and no increase in alg complexity.
All the elements of the vector are removed using clear() function. erase() function, on the other hand, is used to remove specific elements from the container or a range of elements from the container, thus reducing its size by the number of elements removed.
clear(). This method removes all the elements in the Vector. There are no parameters required by the Vector. clear() method and it returns no value.
The naive way is to do an n^2 iteration comparing each element in the first vector against each element in the second array and adding any matches to a third vector. When you finish the n^2 iteration, you walk the third vector and remove those objects from the first two.
If you need to remove multiple elements from the vector, the std::remove will copy each, not removed element only once to its final location, while the vector::erase approach would move all of the elements from the position to the end multiple times.
Sort b
so you can binary search it in order to reduce time complexity. Then use the erase-remove idiom in order to throw away all elements from a
that are contained in b
:
sort( begin(b), end(b) );
a.erase( remove_if( begin(a),end(a),
[&](auto x){return binary_search(begin(b),end(b),x);}), end(a) );
Of course, you can still sacrifice time complexity for simplicity and reduce your code by removing the sort()
and replacing binary_search()
by find()
:
a.erase( remove_if( begin(a),end(a),
[&](auto x){return find(begin(b),end(b),x)!=end(b);}), end(a) );
This is a matter of taste. In both cases you don't need heap allocations. By the way, I'm using lambda auto parameters which are C++14. Some compilers already implement that feature such as clang. If you don't have such a compiler, but only C++11 then replace auto
by the element type of the container.
By the way, this code does not mention any types! You can write a template function so it works for all kind of types. The first variant requires random access iteration of b
while the second piece of code does not require that.
This one does it in O(N+M), assuming both arrays are sorted.
auto ib = std::begin(two);
auto iter = std::remove_if (
std::begin(one), std::end(one),
[&ib](int x) -> bool {
while (ib != std::end(two) && *ib < x) ++ib;
return (ib != std::end(two) && *ib == x);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With