简体   繁体   中英

Quickly find all elements not in a vector c++

I have a vector of points allPoints and a vector of points badPoints . I want to quickly get a set of goodPoints where it is everything in allPoints that is not in badPoints. Currently I have:

    int i = 0;
    for (auto point : allPoints)
    {
        bool add = true;
        for (auto x : badPoints)
        {
            if (point == x)
            {
                add = false;
                break;
            }
        }
        if (add)
        {
            goodPoints.insert(point);
        }
        i++;
    }

I feel like this is slower than it should be but I don't know a better way to do it. Any ideas?

Depending on the dimensions of the points, sorting might not be very viable (you can sort only in one dimension, for example). A better way would be to have a kD tree (eg, if the points are in 2D, make a 2D-tree structure for the points), this way, instead of comparing all the points, you just need to compare with the points in the leaves of the tree.

Another, simpler but not as elegant, way is to divide your space into a grid. For example, if the points are in 2D, divide your plane into a NxN grid, and depending on which grid cell your cells fall in, check for overlap only inside that cell. You need to play with the size of the cells (or N) to find a balance between the number of cells and number of points inside the cells.

In case your data are not sorted, as suggested in the comments, use std::set_difference , like this:

#include <iostream>     // std::cout
#include <algorithm>    // std::set_difference, std::sort
#include <vector>       // std::vector

int main () {
  std::vector<int> allPoints = {5,10,15,20,25};
  std::vector<int> badPoints = {50,40,30,20,10};
  std::vector<int> v(10);                      // 0  0  0  0  0  0  0  0  0  0

  std::sort(allPoints.begin(), allPoints.end());     //  5 10 15 20 25
  std::sort(badPoints.begin(), badPoints.end());   // 10 20 30 40 50

  std::vector<int>::iterator it = std::set_difference(
        allPoints.begin(), allPoints.end(), badPoints.begin(), badPoints.end(), v.begin());
                                                //  5 15 25  0  0  0  0  0  0  0
  v.resize(it - v.begin());                     //  5 15 25

  std::cout << "Good points are " << (v.size()) << " in number:\n";
  for (it=v.begin(); it!=v.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

Georgioss-MacBook-Pro:~ gsamaras$ g++ -Wall -std=c++0x main.cpp 
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out 
Good points are 3 in number:
 5 15 25

Complexity

Up to linear in 2*(count1+count2)-1 (where countX is the distance between firstX and lastX): Compares and assigns elements.

One approach you can do is to utilize use of another data structure called set unique;

Like instead of int, your point structure will come. For simplicity, I am making use of int.

So you implementation will look something like this

set<int> unique;
int i = 0;
for (auto point : badPoints)
{
    unique.insert(point);
}
for(auto point : allPoints)
{
    // it is not present in unique that means it's not a bad point
    if(unique.find(point) == unique.end())
    {
       goodPoints.insert(point);
    }
 }

Hope this helps !

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