Ya que quería que fuera eficiente, creo que se puede conseguir una amortizados O(M)
, suponiendo que tiene para llevar a cabo esa operación muchas veces. Sin embargo, este enfoque no es reentrante.
Primero crea un vector local (es decir, static
) de std::vector<...>::size_type
(es decir, unsigned
hará) valores.
Si introduce su función, cambiar el tamaño del vector para que coincida con N
y llenarlo con los valores del tamaño mayor para N-1
:
static std::vector<unsigned> indices;
if (indices.size() < N) {
indices.reserve(N);
for (unsigned i = indices.size(); i < N; i++) {
indices.push_back(i);
}
}
Entonces, escoja al azar M
números únicos de ese vector:
std::vector<unsigned> result;
result.reserver(M);
for (unsigned i = 0; i < M; i++) {
unsigned const r = getRandomNumber(0,N-i); // random number < N-i
result.push_back(indices[r]);
indices[r] = indices[N-i-1];
indices[N-i-1] = r;
}
Ahora, el resultado está sentado en el vector result
.
Sin embargo, todavía se tiene que reparar sus cambios a indices
para la próxima ejecución, de modo que indices
es monótona nuevo:
for (unsigned i = N-M; i < N; i++) {
// restore previously changed values
indices[indices[i]] = indices[i];
indices[i] = i;
}
Pero este método sólo es útil, si tiene que ejecutar el algoritmo mucho y N
no crece tanto que no puede vivir con indices
comiendo RAM todo el tiempo.
su definición de 'único' se conoce comúnmente como '(dibujo) sin reemplazo' –