2012-02-18 17 views
16

Tengo un vector que contiene n elementos. Necesito elegir un subconjunto de m elementos aleatoriamente del vector sin repetición. ¿Cuál es la forma más eficiente de hacer esto? Necesito hacer esto varias miles de veces en mi código.Elige m elementos al azar de un vector que contiene n elementos

La solución en la parte superior de la cabeza es utilizar rand() para generar un número aleatorio entre k0 y n. A continuación, elija el elemento k en el vector e insértelo en un std::set. Siga haciendo esto hasta que el tamaño del conjunto sea igual a m. Ahora estoy seguro de que el conjunto contiene m elementos únicos elegidos al azar del conjunto de elementos n.

¿Cuáles son las otras soluciones posibles?

Gracias.

+4

hacer en 'std: : random_shuffle() 'en el vector y extraer los primeros elementos' m', tal vez? – jrok

+0

@jrok: aunque es simple, eso es muy poco eficiente cuando 'm' es mucho más pequeño que' n'. –

+0

posible duplicado de [Algoritmo para seleccionar una sola combinación aleatoria de valores?] (Http://stackoverflow.com/questions/2394246/algorithm-to-select-a-single-random-combination-of-values) –

Respuesta

29

¿Quieres una Fisher-Yates shuffle (parada después de iteraciones M):

template<class BidiIter > 
BidiIter random_unique(BidiIter begin, BidiIter end, size_t num_random) { 
    size_t left = std::distance(begin, end); 
    while (num_random--) { 
     BidiIter r = begin; 
     std::advance(r, rand()%left); 
     std::swap(*begin, *r); 
     ++begin; 
     --left; 
    } 
    return begin; 
} 

demo en http://ideone.com/3A3cv. Esto es significativamente más rápido que std::random_shuffle cuando solo necesita unos pocos números aleatorios fuera del conjunto, y debería ser casi la misma velocidad, incluso si N==M.

+0

@ Burr ¡Gracias! Tengo un millón de elementos en mi vector de los cuales necesito elegir solo 100 elementos al azar. Esto es exactamente lo que estaba buscando. – Vinay

+0

¡Gracias por el código! Funciona perfectamente. – Danvil

+2

rand(): vea http://codereview.stackexchange.com/questions/39001/fisher-yates-modern-shuffle-algorithm – dani

3

Una forma de poder hacer esto es crear una lista de todos los índices del vector, mezclarlas, y tomar la primera n ser los índices de los objetos seleccionados:

struct rangegenerator { 
    rangegenerator(int init) : start(init) { } 

    int operator()() { 
     return start++; 
    } 

    int start; 
}; 

vector<T> numbers; // this is filled somewhere else 

vector<int> indices(numbers.size()); 

generate(begin(indices), end(indices), rangegenerator(0)); 

random_shuffle(begin(indices), end(indices)); 

// then take the first n elements of indices and use them as indices into numbers 
+3

Cuando 'm' es mucho más pequeño que' n', esto es altamente ineficiente. No es difícil encontrar una respuesta que sea más rápida que esto para todos los 'm' (donde' m' es menor que 'n') –

+0

@Seth: Tendrán que estar de acuerdo con Moo. Esta es probablemente una de las peores maneras de realizar la tarea determinada, no estoy seguro de por qué OP la marcó como respuesta. La respuesta correcta es obviamente la respuesta de Burr. –

+1

@JaredKrumsie OP solicitó "otras soluciones posibles" y lo que escribí es definitivamente una posible solución. La única forma en que una respuesta sería incorrecta es si no funcionó en absoluto. –

Cuestiones relacionadas