How to insert unique items into vector?

偶尔善良 提交于 2019-12-24 12:43:31

问题


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 pars 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:


  1. There is no getting around iterating over the items in _NeighborPts.
  2. As long as you are using an std::vector, there is no getting around the check to determine whether an item is in NeighborPts 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!