问题
I have a type called Neighbors
:
typedef vector<pair<data,int>> Neighbors;
and here's data
:
struct data
{
int par[PARAMETERS];
int cluster;
bool visited;
bool noise;
};
I'm trying to write a function that inserts values from _NeighborPts
to NeighborPts
(but only ones that aren't already in NeighborPts
):
void insert_unique(Neighbors* NeighborPts, const Neighbors& _NeighborPts)
{
Neighbors_const_it _it = _NeighborPts.begin();
while(_it != _NeighborPts.end())
{
if(/* _it->first.par isn't in *NeighborPts */)
NeighborPts->push_back(*_it);
++_it;
}
}
and i already have a function equal()
which checks if 2 par
s are equal.
So do i have to iterate through NeighborPts
in a while loop and check if the item is found? or could i use some built-in find
or find_if
function to do that for me?
回答1:
You can maintain a sorted vector. Use the lower_bound
function from C++ algorithms to locate the insert position each time. If the element at the insert position is equal to the insert element then you have a duplicate.
The performance of this will be pretty good unless the vector grows too large. The point at which you're better off using a set or a unordered_set varies and you'd need to benchmark to find it.
回答2:
Your current solution with vector will run in O(N^2) time, which is not efficient. For efficient solution an associative container will be great - such as std::set . Also you will need to have some "operator less" (instead of "equal ()"), to pass to the function.
template < class T, // set::key_type/value_type
class Compare = less<T>, // set::key_compare/value_compare
class Alloc = allocator<T> // set::allocator_type
> class set;
So you need to provide compare class
struct data_compare {
bool operator() (const data& lhs, const data& rhs) const{
//...
}
};
set<int64_t, data_compare> exising_items;
You may define such a function, or override "operator <" in struct data.
insert all "data" from "_NeighborPts" into a set - O(N*log(N)) time
std::set other_items; in a loop - iterate _NeighborPts and insert data elements
other_items.insert (_NeighborPts [i]);
std::set my_items; in a loop - iterate _NeighborPts and insert data elements
my_items.insert (NeighborPts [i]);
Now you need to compare between the 2 sets: You can do it using std::set_intersection . or construct a simple loop on the set "my_items" if the current element in other_items isn't in _my_items, insert it in "NeighborPts"
this solution will run in O(Nlog(N)) time
回答3:
- There is no getting around iterating over the items in
_NeighborPts
. - As long as you are using an
std::vector
, there is no getting around the check to determine whether an item is inNeighborPts
before inserting in it.
You can make the code a little bit easier to read by using std::for_each
and a functor.
struct UniqueItemInserter
{
UniqueItemInserter(Neighbors* neighborsIn) : neighbors(neighborsIn) {}
void operator(pair<data,int> const& item)
{
if ( std::find(neighbors->begin(), neighbors->end(), item) != neighbors->end() )
{
neighbors->push_back(item);
}
}
Neighbors* neighbors;
};
void insert_unique(Neighbors* NeighborPts, const Neighbors& _NeighborPts)
{
std::for_each(_NeighborPts.begin(), _NeighborPts.end(), UniqueItemInserter(NeighborPts));
}
来源:https://stackoverflow.com/questions/23844830/how-to-insert-unique-items-into-vector