Ho una raccolta esterna contenente n elementi che voglio selezionare un certo numero (k) di essi casualmente, emettendo gli indici di tali elementi in qualche file di dati serializzato. Voglio che gli indici siano prodotti in ordine crescente e che non ci siano duplicati. Sia n che k possono essere abbastanza grandi e generalmente non è possibile memorizzare semplicemente interi array in memoria di quella dimensione.Come generare un elenco di numeri interi casuali ascendenti
Il primo algoritmo che ho trovato era quello di scegliere un numero casuale r [0] da 1 a nk ... e quindi scegliere un numero casuale successivo r [i] da r [i-1] +1 a n -k + i, ha solo bisogno di memorizzare due voci per "r" in qualsiasi momento. Tuttavia, un'analisi abbastanza semplice rivela che la probabilità di selezionare numeri piccoli è incoerente con quello che avrebbe potuto essere se l'intero set fosse equamente distribuito. Ad esempio, se n era un miliardo e k era mezzo miliardo, la probabilità di selezionare la prima voce con l'approccio che ho appena descritto è molto piccola (1 su mezzo miliardo), dove in realtà dal momento che metà delle voci sono essendo selezionato, il primo dovrebbe essere selezionato il 50% delle volte. Anche se utilizzo l'ordinamento esterno per ordinare k numeri casuali, dovrei scartare qualsiasi duplicato e riprovare. Man mano che k si avvicina a n, il numero di tentativi continuerebbe a crescere, senza alcuna garanzia di risoluzione.
Mi piacerebbe trovare un algoritmo O (k) o O (k log k) per fare ciò, se è possibile. Il linguaggio di implementazione che userò è C++ 11, ma le descrizioni in pseudocodice potrebbero comunque essere utili.
Generare gli interi casuali come al solito (usando 'std :: mt19937' e un' std :: uniform_int_distribution' per esempio) e memorizzare i risultati in un 'std :: set' tale che non ci siano duplicati e il risultante il contenitore è ordinato intrinsecamente. –
ArchbishopOfBanterbury
È sempre necessario selezionare esattamente k elementi? O è accettabile per il conteggio medio di molte esecuzioni tendenzialmente verso k? In quest'ultimo caso, aggiungere semplicemente RND (0, 2n/k) a ciascuna voce precedente fino a raggiungere la fine dell'elenco. –
Sempre in ordine crescente. Nessun deposito. Nessuna duplicazione È una cosa difficile da fare. Dovrò pensare se questo sia persino possibile. – user4581301