2012-05-10 9 views
7

In meinem Algorithmus habe ich zwei Werte, die ich zufällig auswählen muss, aber jede muss eine bestimmte Anzahl von Malen gewählt werden.Zufällige Auswahl von zwei Werten

Bis jetzt ist meine Lösung, die Wahlen in einen Vektor die korrekte Anzahl von Zeiten zu setzen und dann es zu mischen. In C++:

// Example choices (can be any positive int) 
int choice1 = 3; 
int choice2 = 4; 

int number_of_choice1s = 5; 
int number_of_choice2s = 1; 

std::vector<int> choices; 
for(int i = 0; i < number_of_choice1s; ++i) choices.push_back(choice1); 
for(int i = 0; i < number_of_choice2s; ++i) choices.push_back(choice2); 
std::random_shuffle(choices.begin(), choices.end()); 

Dann halte ich einen Iterator auf choices und wann immer ich einen neuen brauchen erhöhe ich den Iterator und diesen Wert greifen.

Das funktioniert, aber es scheint, als könnte es einen effizienteren Weg geben. Da ich immer weiß, wie viele von jedem Wert ich verwenden werde, frage ich mich, ob es einen algorithmischeren Weg gibt, dies zu tun, anstatt nur die Werte zu speichern.

+0

Ich würde mit der Arbeitslösung bleiben, es sei denn, es gibt einen guten Grund, warum nicht. Wird es als Engpass oder ähnliches profiliert? – amit

+0

Es gibt einen Weg, aber es wäre weniger klar und prägnant. Ich würde bei dieser Technik bleiben. –

+0

Ich mag diese Lösung wirklich so, wie sie ist. Alle anderen Lösungen, die Ihnen in den Sinn kommen (nachdem Sie etwa 5 Sekunden lang darüber nachgedacht haben), betreffen Zufallszahlengeneratoren. Aber da Sie eine vorbestimmte Anzahl von jeder Wahl haben, wären diese Lösungen ineffektiv, da sie letztendlich Werte ignorieren müssten, nachdem ihre Wahl bereits die maximale Anzahl von Malen aufgetreten ist. (zugegebenermaßen ist die Shuffle-Methode möglicherweise ein CPU-Drain, aber Sie können es zumindest zu einer vorhersagbaren Laufzeit machen, was Sie mit den oben erwähnten Lösungen nicht tun können) – gnomed

Antwort

10

Sie verbrauchen unnötig viel Speicher. Sie haben zwei Variablen:

int number_of_choice1s = 5; 
int number_of_choice2s = 1; 

Jetzt randomisieren einfach:

int result = rand() % (number_of_choice1s + number_of_choice2s); 
if(result < number_of_choice1s) { 
    --number_of_choice1s; 
    return choice1; 
} else { 
    --number_of_choice2s; 
    return choice2; 
} 

Diese sehr gut zwei Millionen von zufälligen Anrufungen skaliert.

+0

Sobald einer der Zähler 0 erreicht, können Sie den Rest des Prozesses kurzschließen. –

+0

Wie ist der Bias? Das sieht nur aus wie eine angepasste Version von Knuths Select m from n -Algorithmus - +1 von mir – BrokenGlass

+2

Aber beachte, dass wenn deine Standard-Bibliothek zufälligerweise eine schlechte 'rand'-Implementierung hat (zB linear kongruent mit kleinerem Modul), benutze% So kann Bias eingeführt werden. Außerdem kann "RAND_MAX" so klein wie 32767 sein (der 'Rand' in der Microsoft-Standardbibliothek hat diese Eigenschaft) und Sie werden völlig verlieren, wenn Sie eine große Anzahl von Möglichkeiten haben. –

1

Man könnte dies einfach ein bisschen mehr schreiben:

std::vector<int> choices(number_of_choice1s, choice1); 
choices.resize(number_of_choice1s + number_of_choice2s, choice2); 
std::random_shuffle(choices.begin(), choices.end()); 
0

Eine voreingenommen zufällige Verteilung wird eine Art von Ordnung über die sich ergebende Satz (die Wahl halten, die am meisten aufgenommen wurde haben immer weniger Chance ausgewählt werden als nächstes), die ein verzerrtes Ergebnis liefern (besonders wenn die Anzahl der Zeit, die Sie für den ersten Wert benötigen, groß im Vergleich zum zweiten Wert ist, erhalten Sie etwas Ähnliches {1,1,1,2,1,1 , 1,1,2}.

Hier ist der Code, der dem von @Tomasz Nurkiewicz geschriebenen ähnelt, aber ein einfaches even/odd verwendet, das ungefähr 50/50 Chance geben sollte, entweder va auszuwählen Lues.

int result = rand(); 

if (result & 1 && number_of_choice1s > 0) 
{ 
number_of_choice1s--; 
return choice1; 
}else if (number_of_choice2s>0) 
{ 
number_of_choice2s--; 
return choice2; 
} 
else 
{ 
return -1; 
} 
Verwandte Themen