Der folgende deterministische Algorithmus (ohne Komparator) funktioniert für ein Eingabetupel :(a1,…,an)
- Führen Sie den Fisher-Yates-Shuffle mit Ihrem Komparator mit einem statischen Paar (z. B. ) als Münzwurf durch (Abtastung von Akzeptanz und Ablehnung). Wenn der Komparator das erste Mal ausgibt , verwenden Sie ihn invertiert, um im deterministischen Fall eine endlose Zurückweisungsschleife zu vermeiden. 1a1<a21
- (Optionale Beschleunigung: Versuchen Sie ein einzelnes Paar mal, wobei die Länge oder Ihre Eingabe ist. Wenn sich zwei der Ausgaben unterscheiden, geben Sie die in (1) erhaltene Permutation zurück.)nnn
- Sortieren Sie Ihr Array mithilfe der Zusammenführungssortierung.
Bei einer deterministischen Ordnungsbeziehung als Komparator sortiert dieser Algorithmus ein Array in der Zeit da die Fisher-Yates-Zufallswiedergabe in Verwendung von maximal Nicht zufällige "Zufallsbits" (z. B. Aufrufe Ihres Komparators) in jedem Schritt und Zusammenführungssortierung haben dieselbe asymptotische Komplexität. Das Ergebnis von (1) ist in diesem Fall völlig nutzlos, aber da es von einer echten Art gefolgt wird, schadet dies nicht.O ( n ) O ( log n )O(nlogn)O(n)O(logn)
Wenn ein echter Münzwurf als Komparator (1) das Array mit gleicher Wahrscheinlichkeit für jede Permutation permutiert und wenn Sie wirklich (3) tun müssen (Sie haben (2) oder (2) ausgelassen, um die Zufälligkeit nicht zu bestimmen), ist dies nein Schaden, weil die Verteilung seines Ergebnisses nur von der Reihenfolge seiner Eingabe abhängt, die aufgrund von (1) gleichmäßig auf alle Permutationen verteilt ist, so dass auch das Ergebnis des gesamten Algorithmus gleichmäßig verteilt ist. Die Häufigkeit, mit der jede Akzeptanz-Zurückweisungs-Abtastung wiederholt werden muss, ist geometrisch verteilt (Zurückweisung mit der Wahrscheinlichkeit ) und hat daher einen erwarteten Wert . Jede Wiederholung verwendet höchstens Bits, sodass die Laufzeitanalyse fast dieselbe ist wie im deterministischen Fall, aber wir erhalten nur eine <2lognO(nlogn)<12<2lognerwartete Laufzeit von mit der Möglichkeit der Nichtbeendigung (endet nur fast sicher ).O(nlogn)
Wie Joe betonte: Wenn Ihnen der Test für das erste Bit in (1) nicht gefällt, machen Sie (3) und dann (1) und verwenden Sie das immer , da das Array im deterministischen Fall bereits sortiert ist . Zusätzlich müssen Sie Ihre Zufallszahl von der Obergrenze des Bereichs in der Schleife subtrahieren, da die Obergrenze für die Zufallszahl die identische Permutation ergibt. Beachten Sie jedoch, dass (2) dann verboten ist, da Sie im Lösegeldfall immer mischen müssen.an<a10
Sie können für (1) und (3) sogar dieselben Aufrufe an Ihren Komparator verwenden, aber dann zu beweisen, dass das Ergebnis gleichmäßig verteilt ist, ist zumindest viel schwieriger, wenn überhaupt möglich.
Der folgende Algorithmus hat keine unterschiedlichen Phasen zum Mischen und Sortieren, ist jedoch asymptotisch langsamer. Es handelt sich im Wesentlichen um eine
Einfügesortierung mit
binärer Suche . Ich werde , um die Eingabe zu bezeichnen, und , um das Ergebnis nach der ten Runde zu bezeichnen:
a=(a1,…,an)bk=(bk,1,…,bk,k)k
- Setzeb1,1=a1
- Wenn dann ist und sonst und . In beiden Fällen ist für einen nicht zufälligen Komparator immer (dh falsch).a2<a1b2=(a2,a1)(c,d):=(2,1)b2=(a1,a2)(c,d):=(1,2)ad<ac0
- Um für erhalten, erhalten Sie zuerst .bkk≥3bk−1
- Sei und , dh ist die kleinste Potenz von nicht kleiner als .l=⌈log2k⌉k′=2lk′2k
- Sei . Für jedes lasse
i0=0j∈{1,…,l}
ij=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪ij−1+2l−jij−1ij−1+2l−jij−1ij−1+2l−j>k−1∧ad<acij−1+2l−j>k−1∧¬(ad<ac)ij−1+2l−j≤k−1∧bk−1,ij−1+2l−j<akij−1+2l−j≤k−1∧¬(bk−1,ij−1+2l−j<ak)
- Wenn (5.) wiederholen, sonstb k = ( b k - 1 , 1 , ... , b k - 1 , i l - 1 , a k , b k - 1 , i l , ... , b k - 1 , k - 1 )il>kbk=(bk−1,1,…,bk−1,il−1,ak,bk−1,il,…,bk−1,k−1)
- Ausgabebn
Zufälliger Fall: 5 + Die if-Klausel von 6 ist im Wesentlichen eine Akzeptanz-Ablehnungs-Stichprobe. Der Rest des Algorithmus ist ein naives Mischen: Mischen Sie die ersten Elemente und fügen Sie das te Element mit gleicher Wahrscheinlichkeit zu jeder Position hinzu. Wenn wir die normale Einfügungssortierung verwenden würden, würden wir stattdessen eine Binomialverteilung erhalten.kk−1k
Beachten Sie, dass dieser Algorithmus in beiden Modi im Vergleich zum Fisher-Yates-Shuffle- und Merge-Sortieren ineffizient ist, da das Einfügen eines Elements an eine beliebige Position teuer ist, wenn ein Array verwendet wird und die binäre Suche bei Verwendung einer Liste lineare Zeit benötigt. Aber vielleicht könnte eine Modifikation der Heap-Sortierung oder der Baumsortierung auf ähnliche Weise zu einem schnelleren Algorithmus führen.