Skip to content

Instantly share code, notes, and snippets.

@matovitch
Last active April 6, 2022 17:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matovitch/1c262d2d870024ca0b81 to your computer and use it in GitHub Desktop.
Save matovitch/1c262d2d870024ca0b81 to your computer and use it in GitHub Desktop.
container with O(1) insertion, deletion, and pick random
#include <vector>
#include <random>
#include <cstddef>
#include <functional>
#include <unordered_set>
template <typename T, typename H = std::hash<T> >
struct Hasher
{
std::size_t operator()(const T* const pt) const
{
return H()(*pt);
}
};
template <class T, typename H = std::hash<T>>
struct EqualTo
{
bool operator() (const T* x, const T* y) const
{
return Hasher<T, H>()(x) == Hasher<T, H>()(x);
}
};
template <typename T, typename H = std::hash<T> >
struct PickSet
{
void rebuildAndReserve()
{
_unorderedSet.clear();
_unorderedSet.reserve(_vector.capacity());
for (const T& t : _vector) _unorderedSet.insert(&t);
}
void insert(const T& t)
{
if (_unorderedSet.find(&t) == _unorderedSet.end())
{
_vector.push_back(t);
if (_unorderedSet.find(&(*(_vector.cbegin()))) != _unorderedSet.end())
{
_unorderedSet.insert(&(*(_vector.crbegin())));
}
else
{
rebuildAndReserve();
}
}
}
void erase(const T& t)
{
auto fit = _unorderedSet.find(&t);
if (fit != _unorderedSet.end())
{
if (*fit != &(*(_vector.crbegin())))
{
*(const_cast<T*>(*fit)) = *(_vector.rbegin());
}
_vector.pop_back();
}
}
const T& pickRandom() const
{
return _vector[_distribution(_generator) % _vector.size()];
}
std::unordered_set<const T*, Hasher<T, H>, EqualTo<T, H> > _unorderedSet;
std::vector<T> _vector;
static std::default_random_engine _generator;
static std::uniform_int_distribution<std::size_t> _distribution;
};
template <typename T, typename H>
std::default_random_engine PickSet<T, H>::_generator = std::default_random_engine();
template <typename T, typename H>
std::uniform_int_distribution<std::size_t> PickSet<T, H>::_distribution = std::uniform_int_distribution<std::size_t>();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment