Mathematik online lernen im Mathe-Forum. Nachhilfe online
Startseite » Forum » Zufallspermutationen

Zufallspermutationen

Universität / Fachhochschule

Tags: permutation, Zufall

 
Antworten Neue Frage stellen Im Forum suchen
Neue Frage
Sukomaki

Sukomaki aktiv_icon

11:43 Uhr, 11.08.2024

Antworten
Guten Morgen,

wie lässt sich eine zufällige Permutation in Laufzeit O(n) berechnen?

Ich habe zuerst verschiedene Ansätze verfolgt. Die hatten aber wesentlich schlechtere Laufzeiten.

Der allernaivste Ansatz wäre :

1. Starte mit einer leeren Liste!
2. Bestimme eine Zufallszahl, die noch nicht in der Liste ist!
3. Füge diese der Liste hinzu!
4. Gehe zu 2. und breche ab, wenn die Liste voll ist!

(Für größere n wird das allerdings ultra langsam und es kann sogar der Fall
auftreten, dass der Algorithmus nicht terminiert, nämlich wenn alle Zufallszahlen
schon vergeben sind.)

Schließlich habe ich eine Permutation der Länge 5.000.000 in 3,37 Sek. in Python berechnen lassen.

Ich glaube, viel schneller geht das nicht.

Zumindest nicht in Python :-)

Weiß jemand, wie ich das geschafft habe?

Tipp : Das Einfügen einer neuen Zahl hat konstante Laufzeit O(1) und es müssen keine Elemente gelöscht werden.

Ich bin schon gespannt, ob jemand einen schnelleren Algorithmus findet, oder drauf kommt,
wie ich das gemacht habe.

G
Sukomaki

EDIT : In C++ läuft die Permutation mit 5.000.000 Elementen in 69 bis 87 Millisekunden.


Für alle, die mir helfen möchten (automatisch von OnlineMathe generiert):
"Ich möchte die Lösung in Zusammenarbeit mit anderen erstellen."
Online-Nachhilfe in Mathematik
Antwort
HAL9000

HAL9000

14:54 Uhr, 12.08.2024

Antworten
import time, random

def permrandom(n):
p = list(range(1,n+1))
for i in range(n-1,1,-1):
j = random.randint(0,i)
p[i],p[j] = p[j],p[i]
return p

if __name__ == '__main__':
time_start = time.time()
p = permrandom(5000000)
time_end = time.time()
print(f"running time {time_end-time_start:.3f} s")

Leider "zerstört" das Forum hier die notwendigen Python-Einrückungen...
Bei mir ergab das eine Laufzeit von ca. 2.3 Sekunden - ist natürlich CPU-abhängig.

Der Hauptteil der Zeit dürfte wohl auf die Zufallszahlgenerierung draufgehen. Der Elementaustausch in der Liste ist demgegenüber eher vernachlässigbar.
Sukomaki

Sukomaki aktiv_icon

16:07 Uhr, 12.08.2024

Antworten
Das ist interessant :

Von der Idee her gehst Du genau so vor wie ich :-)

Du kannst, wenn Du einen Array statt einer Liste verwendest noch mal 9% bis 13%
Geschwindigkeitsvorteil rausholen.

Meine CPU hat einen Takt von 2,6 GHz. Und Deine?

> Der Hauptteil der Zeit dürfte wohl auf die Zufallszahlgenerierung draufgehen

Das sehe ich genau so.

G
Sukomaki

Antwort
HAL9000

HAL9000

11:17 Uhr, 13.08.2024

Antworten
i7-13800H mit bis zu 5.2GHz

(Die 14 Kerne dürften bei dem Algorithmus nichts nützen, wenn man nur eine einzige solche Permutation berechnen will, da dann das Vorgehen hier nicht parallelisierbar ist.)

Mit array ("L" für 32Bit-Werte) ist es tatsächlich etwas schneller, so ca. 1.9 Sekunden.
Sukomaki

Sukomaki aktiv_icon

15:42 Uhr, 13.08.2024

Antworten
Ich hoffe, Dir hat die Herausforderung Spaß gemacht. Ich erinnere mich daran, dass Du Dich für das Thema "Wahrscheinlichkeit einer fixpunktfreien Permutation" begeistert hast.

Zum Nachvollziehen an alle andere :

Wir starten mit einer sortierten Liste. Im ersten Schritt wählen wir eine zufällige Zahl und tauschen Sie mit der hintersten Zahl. Natürlich kann die gezogene Zahl auch die größte Zahl sein. Die bleibt dann eben an Ihrem Platz. Im zweiten Schritt wählen wir eine Zahl mit Index 0 bis n-2, also einer weniger als vorher. Die tauschen wir auf den vorletzten Platz. So geht das weiter. Nach dem j-ten Schritt gilt : Die j letzten Zahlen verbleiben an Ihrer Position, die ersten Zahlen werden weiter durchgewürfelt. So erhalten wir am Schluß eine zufällige Permutation.

Bemerkung : Es wäre noch die Korrektheit des Algorithmus zu zeigen. Ich vermute, das läuft auf einen Induktionsbeweis hinaus. Den bekomme ich auf die Schnelle aber nicht hin.

Sukomaki
Antwort
HAL9000

HAL9000

16:11 Uhr, 13.08.2024

Antworten
> Ich erinnere mich daran, dass Du Dich für das Thema "Wahrscheinlichkeit
> einer fixpunktfreien Permutation" begeistert hast.

Na, die Begeisterung dafür ist 30 Jahre her. Letztens habe ich nur mein Wissen darüber dargelegt. ;-)

Frage beantwortet
Sukomaki

Sukomaki aktiv_icon

08:42 Uhr, 14.08.2024

Antworten
Danke für's Mitmachen.

Es hat mir Spaß gemacht.

Und nebenbei habe ich noch etwas Python gelernt.

> if __name__ == '__main__':

kannte ich noch nicht.

Und das elegante Austauschen zweier Elemente

> p[i],p[j] = p[j],p[i]

gefällt mir auch gut.

Sukomaki

Antwort
HAL9000

HAL9000

15:45 Uhr, 15.08.2024

Antworten
> Und nebenbei habe ich noch etwas Python gelernt.
> if __name__ == '__main__':

Ja, dient der Doppelverwendung ein- und desselben Codes mal als Hauptprogramm und dann wieder als Modul (wo man diesen Zweig oben nicht braucht).
Sukomaki

Sukomaki aktiv_icon

10:29 Uhr, 19.08.2024

Antworten
Aha, okay, danke für die Info.

Muss ich das verstehen?

Ein Modul ist doch etwas, was importiert wird.


Antwort
HAL9000

HAL9000

10:51 Uhr, 19.08.2024

Antworten
Genau, und als importiertes Modul würde der obige Code nur die Routine "permrandom" importieren, nicht aber den main-Code (und diesen natürlich dann auch nicht ausführen).
Frage beantwortet
Sukomaki

Sukomaki aktiv_icon

15:33 Uhr, 20.08.2024

Antworten
Noch einmal abgehakt.