I need a data structure that satisfies the following:
- stores an arbitrary number of elements, where each element is described by 10 numeric metrics
- allows fast (
log n
) search of elements by any of the metrics - allows fast (
log n
) insertion of new elements - allows fast (
log n
) removal of elements
And let's assume that the elements are expensive to construct.
I came up with the following plan
- store all elements in a vector called DATA.
- use 10
std::sets
, one for each of 10 metrics. Eachstd:set
is light-weight, it contains only integers, which are indexes into the vectorDATA
. The comparison operators 'look up' the appropriate element in DATA and then select the appropriate metric
template< int C >
struct Cmp
{
bool operator() (int const a, int const b)
{
return ( DATA[a].coords[C] != DATA[b].coords[C] )
? ( DATA[a].coords[C] < DATA[b].coords[C] )
: ( a < b );
}
};
Elements are never modified or removed from a vector. A new element is pushed back to DATA and then its index (DATA.size()-1
) is inserted into the sets (set<int, Cmp<..> >
). To remove an element, I set a flag in the element saying that it is deleted (without actually removing it from the DATA
vector) and then remove the element index from all ten std::sets.
This works fine as long as DATA
is a global variable. (It also somewhat abuses the type system by making the templated struct Cmp dependent on a global variable.)
However, I was not able to enclose the DATA
vector and std::set's (set<int, Cmp<...> >
) inside a class and then 'index' DATA
with those std::sets
. For starters, the comparison operator Cmp defined inside an outer class has no access to the outer class' fields (so it cannot assess DATA). I also cannot pass the vector to the Cmp constructor because Cmp is being constructed by std::set and std::set expects a comparison operator with a constructor that has no arguments.
I have a feeling I'm working against C++ type system and trying to achieve something that the type system is purposely preventing me from doing. (I'm trying to make std::set depend on a variable that is going to be constructed only at runtime.) And while I understand why the type system might not like what I do, I think this is a legitimate use case.
Is there a way to implement the data structure/class I described above without providing a re-implementation of std::set/red-black tree? I hope there may be a trick I have not thought of yet. (And yes, I know that boost has something, but I'd like to stick to the standard library.)