Si el acceso aleatorio es importante y puede vivir con un esfuerzo promedio de O (N) para la inserción, la solución dada en this paper podría ser conveniente.
La idea principal es utilizar un vector clasificado, y luego para buscar la función std::lower_bound
. Esto, la búsqueda toma O (log N) como en un conjunto normal. Además, la inserción (aleatoria) toma O (N), ya que todos los elementos siguientes deben desplazarse al igual que en un vector normal (y posiblemente se realice una reasignación). Sin embargo, la inserción en la parte posterior es constante (a excepción de la reasignación. Puede evitar esto llamando al reserve()
con un almacenamiento lo suficientemente grande).
Finalmente, el punto principal de la pregunta: El acceso aleatorio es O (1). Simplemente dibuje un número al azar i
de una distribución uniforme en [0, V.size()-1]
, y devuelva el elemento correspondiente V[i]
.
Aquí está el código base del papel, que implementa este vector ordenado. Extenderlo según sea necesario:
template <class T, class Compare = std::less<T> >
struct sorted_vector {
using std::vector;
using std::lower_bound;
vector<T> V;
Compare cmp;
typedef typename vector<T>::iterator iterator;
typedef typename vector<T>::const_iterator const_iterator;
iterator begin() { return V.begin(); }
iterator end() { return V.end(); }
const_iterator begin() const { return V.begin(); }
const_iterator end() const { return V.end(); }
//...if needed, implement more by yourself
sorted_vector(const Compare& c = Compare()) : V(), cmp(c) {}
template <class InputIterator>
sorted_vector(InputIterator first, InputIterator last, Const Compare& c = Compare())
: V(first, last), cmp(c)
{
std::sort(begin(), end(), cmp);
}
//...
iterator insert(const T& t) {
iterator i = lower_bound(begin(), end(), t, cmp);
if (i == end() || cmp(t, *i))
V.insert(i, t);
return i;
}
const_iterator find(const T& t) const {
const_iterator i = lower_bound(begin(), end(), t, cmp);
return i == end() || cmp(t, *i) ? end() : i;
}
};
Para una aplicación más sofisticada, también se podría considerar this page.
EDITAR: o mejor aún, utilizar boost::container::flat_set
, que implementa el conjunto utilizando la idea anterior, es decir, como un vector ordenado.
Tenga cuidado al usar el módulo (%) en la generación de números aleatorios, la distribución puede no ser exactamente igual (el último elemento es menos probable que los demás). –
[El sesgo de módulo es algo que debe considerar cuando s.size() es grande en comparación con 'RAND_MAX'] (http://stackoverflow.com/a/16006723/111307) – bobobobo
Posible duplicado de https://xkcd.com/ 221/ –