Hallo,
ja, es ist schneller, auch bei so vielen Zahlen, allerdings braucht es halt ein bisschen mehr Speicherplatz. Wie andere schon sagten, es wäre schon hilfreich zu wissen, was genau du denn für Zufallszahlen berechnen willst.
Wenn es darum geht, eine zufällige Permutation aller Zahlen zu berechnen, geht es mit der vorher beschriebenen Funktion.
Falls du aus einer sehr großen Menge an Zahlen nur ein paar zufällig ziehen willst, sollte man es dagegen anders machen, um nicht zuviel Speicherplatz zu verbrauchen.
Eine einfache Möglichkeit wäre dann z.B., einfach immer eine Zufallszahl zu generieren, und hinterher zu prüfen, ob sie bereits gezogen wurde, und wenn ja, dann generiert man nochmal eine. Das ist allerdings im mathematischen Sinne nicht ganz korrekt, denn man zieht ja immer nur aus einer bestimmten Menge, von der die vorher gezogenen Zahlen schon entfernt wurden.
Man kann aber beispielsweise das Array, in dem alle möglichen Zahlen drin stehen, nur simulieren und sich die bereits gezogenen Indizes merken. Dann generiert man einen Index aus dem Bereich der noch vorhandenen Zahlen und erhöht ihn soweit, dass er einem Index aus dem simulierten Array entspricht, dessen Zahl noch nicht gezogen wurde. Beispiel:
Public Function ZufallszahlenOhneZuruecklegenGross(Min As Long, _
AnzVorhandenerZahlen As Long, Einheit As Long, Anzahl As Long) as Long()
Dim i As Long, j As Long, z As Long, Length As Long
Length = AnzVorhandenerZahlen 'Anzahl vorhandener Zahlen
Dim VergebeneIndizes() As Long ' Die schon vergebenen Indizes
Dim Zahlen() As Long 'ergebnis
ReDim VergebeneIndizes(Anzahl - 1)
ReDim Zahlen(Anzahl - 1)
For i = 0 To Anzahl - 1
Dim index As Long
index = Int(Rnd * Length) 'Index heraussuchen
'Jetzt nachschauen, um wieviel der Index nach oben korrigiert werden
' muss
For j = 0 To i - 1
If index >= VergebeneIndizes(j) Then
index = index + 1 ' erhöhen
Else
Exit For
End If
Next
Dim EinfuegeIndex As Long
EinfuegeIndex = -binarySearch(VergebeneIndizes, 0, i, index) - 1
For z = i - 1 To EinfuegeIndex Step -1
VergebeneIndizes(z + 1) = VergebeneIndizes(z)
Next
VergebeneIndizes(EinfuegeIndex) = index
Zahlen(i) = index * Einheit + Min
Length = Length - 1
Next
ZufallszahlenOhneZuruecklegenGross = Zahlen
End Function
Private Function binarySearch(a() As Long, fromIndex As Long, toIndex As Long, _
key As Long) As Long
Dim low As Long, high As Long
low = fromIndex
high = toIndex - 1
Do While low <= high
Dim mid As Long, midVal As Long
mid = (low + high) \ 2
midVal = a(mid)
If midVal < key Then
low = mid + 1
ElseIf midVal > key Then
high = mid - 1
Else
binarySearch = mid 'Key gefunden
Exit Function
End If
Loop
binarySearch = -(low + 1) ' Key nicht gefunden
End Function Parameter der Funktion:
Min: Das Minimum der Zahlen
AnzVorhandenerZahlen: Die Anzahl der vorhandenen Zahlen, die gezogen werden können
Einheit: Die Schrittweite der vorhandenen Zahlen, also z.B. 1, wenn die Zahlen 1, 2, 3, usw. sind. Wenn man Gleitkommazahlen bräuchte, müsste man den Typ des Zahlen-Arrays auf Double ändern.
Anzahl: Die Anzahl der zu ziehenden Zahlen.
Aufrufbeispiel:Randomize
Dim Zahlen() As Long
Zahlen = ZufallszahlenOhneZuruecklegenGross(10000, (6000000 - 10000 + 1), 1, _
100) Das bedeutet, dass aus der Zahlenmenge {10000, 10001, 10002, ..., 5999998, 5999999, 6000000} genau 100 Zahlen ohne Zurücklegen gezogen werden (also bereits gezogene Zahlen werden nicht mehr erneut gezogen).
Allerdings ist diese Funktion viel langsamer als die vorher gepostete, wenn sehr viele Zahlen gezogen werden. Wenn dagegen aus einer sehr großen Menge nur wenige Zahlen gezogen werden, ist sie schneller und braucht nur sehr wenig Speicher.
Beitrag wurde zuletzt am 05.05.11 um 14:07:49 editiert. |