smw
smw

Reputation: 477

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?

Upvotes: 1

Views: 837

Answers (3)

zenwraight
zenwraight

Reputation: 2000

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 !

Upvotes: 0

gsamaras
gsamaras

Reputation: 73366

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.

Upvotes: 1

triple_r
triple_r

Reputation: 1047

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 (e.g., 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.

Upvotes: 2

Related Questions