definisco un unordered_map
come questo:Selezionare elemento casuale in un unordered_map
std::unordered_map<std::string, Edge> edges;
C'è un modo efficace per scegliere un bordo a caso dai bordi unordered_map?
definisco un unordered_map
come questo:Selezionare elemento casuale in un unordered_map
std::unordered_map<std::string, Edge> edges;
C'è un modo efficace per scegliere un bordo a caso dai bordi unordered_map?
Questo è come è possibile ottenere elemento casuale da una mappa:
std::unordered_map<std::string, Edge> edges;
iterator item = edges.begin();
int random_index = rand() % edges.size();
std::advance(item, random_index);
Oppure dare un'occhiata a this answer, che fornisce la seguente soluzione:
std::unordered_map<std::string, Edge> edges;
iterator item = edges.begin();
std::advance(item, random_0_to_n(edges.size()));
Pre-C++ soluzione 11 :
std::tr1::unordered_map<std::string, Edge> edges;
std::tr1::unordered_map<std::string, Edge>::iterator random_it = edges.begin();
std::advance(random_it, rand_between(0, edges.size()));
C++ 11 in poi soluzione:
std::unordered_map<std::string, Edge> edges;
auto random_it = std::next(std::begin(edges), rand_between(0, edges.size()));
La funzione che seleziona un numero casuale valida è fino a vostra scelta, ma essere sicuri che restituisce un numero nella gamma [0 ; edges.size() - 1]
quando edges
non è vuoto.
La funzione std::next
avvolge semplicemente la funzione std::advance
in un modo che consente l'assegnazione diretta.
Ricordare 'rand_between (0, edges.size())' potrebbe restituire 'edges.size()' e 'random_it' punterà su' edges.end() '. Suggerirei 'rand_between (0, edges.size() - 1)' ma dobbiamo essere certi che 'edges' non sia vuoto. –
Sì, deve essere nell'intervallo '[0, edge.size() ['. – Chnossos
Quale sarebbe la complessità temporale della seconda soluzione? È necessario eseguire in modo indipendente n chiavi casuali per recuperare l'ennesima chiave casuale? – blueman
Esiste un modo efficace per scegliere un Edge casuale dai bordi unordered_map?
Se per efficiente si intende O (1), quindi no, non è possibile.
Poiché gli iteratori restituiti da unordered_map::begin/end
sono ForwardIterator
s, gli approcci che utilizzano semplicemente std::advance
sono O (n) nel numero di elementi.
Se l'uso specifico lo consente, è possibile barattare un po 'di casualità per l'efficienza:
È possibile selezionare un casuale secchio (cui si può accedere in O (1)), e poi un elemento casuale all'interno di quella secchio.
int bucket, bucket_size;
do
{
bucket = rnd(edges.bucket_count());
}
while ((bucket_size = edges.bucket_size(bucket)) == 0);
auto element = std::next(edges.begin(bucket), rnd(bucket_size));
Dove rnd(n)
restituisce un numero casuale nella 0, n range [).
In pratica, se si dispone di un hash decente, la maggior parte dei bucket conterrà esattamente un elemento, altrimenti questa funzione privilegerà leggermente gli elementi che sono soli nei rispettivi bucket.
Questo è un metodo elegante! Tuttavia, c'è un piccolo problema: 'std :: advance' non restituisce un iteratore, invece, dovresti usare' std :: next'. –
fisso @for_stack, grazie – sbabbi
Con quel ciclo while non c'è alcuna garanzia che il tuo metodo restituirà qualcosa. Probabilmente non ci si imbatterà in questo, ma se la mappa non è densamente popolata, potrebbe trasformarsi in un problema. –
Strict O (1) soluzione senza secchi:
Tuttavia, vi è una limitazione: se si desidera eliminare elementi dalla mappa oltre al prelievo casuale, è necessario correggi il tuo vettore chiave, questo prende O (n) con un approccio ingenuo. Ma c'è ancora un modo per ottenere prestazioni O (1): tieni una mappa che ti dice dove si trova la chiave nel vettore chiave e aggiornala con lo scambio :)
Che cosa stai usando adesso? E hai profilato che questo metodo è un collo di bottiglia? – Borgleader
possibile duplicato di [Elemento casuale in una mappa] (http://stackoverflow.com/questions/158836/random-element-in-a-map) – Chnossos