QuickSort

Einer der bekanntesten Algorithmen zur Sortierung ist QuickSort. Es handelt sich um einen Divide-and-Conquer-Ansatz, bei dem in jedem Schritt ein Pivot-Element aus dem Array ausgewählt wird. Anschließend wird das Array in drei Teile aufgeteilt: Alle Elemente, die kleiner als das Pivot sind, kommen nach links, die dem Pivot entsprechenden Elemente in die Mitte, und die größeren Elemente nach rechts. Dieses Vorgehen wird wiederholt, bis das gesamte Array sortiert ist.
Anders ausgedrückt, wird in jeder Iteration Folgendes getan:
  1. Ein Pivot-Element aus dem Array wählen
  1. Alle kleineren Elemente in den linken Teil verschieben
  1. Alle größeren Elemente in den rechten Teil verschieben
  1. Alle dem Pivot entsprechenden Elemente in der Mitte zusammenfassen
  1. Dasselbe Verfahren rekursiv auf den linken und den rechten Teil anwenden
def quicksort(a):
    if len(a) <= 1:
        return a
    pivot = a[len(a) // 2]
    left = [x for x in a if x < pivot]
    middle = [x for x in a if x == pivot]
    right = [x for x in a if x > pivot]
    return quicksort(left) + middle + quicksort(right)
Diese QuickSort-Implementierung verwendet zusätzliche Arrays für die Teile left, middle und right. Man kann sie jedoch auch in-place gestalten, indem man die Elemente mithilfe von Indizes direkt im Array umordnet:
def quicksort(a, start, end):
    if start >= end:                    # Keine Elemente zum Sortieren
        return

    pivot = a[start]                    # Wähle ein Pivot-Element
    l, r = start + 1, end               # Sortiere a[start+1 ... end]
    while l <= r:                       # Solange es noch Elemente im Bereich gibt
        if a[l] < pivot:                # wenn a[l] < pivot => belasse a[l] wie es ist
            l += 1                      # Linken Zeiger erhöhen
        else:                           # ansonsten verschiebe a[l] ans Ende
            a[l], a[r] = a[r], a[l]     # Vertausche a[l] und a[r] -> verschiebe ans Ende
            r -= 1                      # Rechten Zeiger verringern

    a[start], a[r] = a[r], a[start]     # Vertausche pivot mit a[r]
    quicksort(a, start, r - 1)          # Sortiere a[start ... r-1]
    quicksort(a, r + 1, end)            # Sortiere a[r+1 ... end]
Vielleicht ist dir aufgefallen, dass das Pivot-Element in den beiden Implementierungen unterschiedlich gewählt wird. Der QuickSort-Algorithmus legt sich nicht auf eine bestimmte Wahl des Pivots fest. Es gibt verschiedene Strategien dafür, unter anderem:
  1. Erstes Element: a[start] (wie im zweiten Beispiel gezeigt)
  1. Letztes Element: a[end]
  1. Mittleres Element: a[(start + end + 1) // 2]
  1. Zufälliges Element: Beliebiges Element in a[start ... end] wählen
  1. Median-Element: Das Median-Element des aktuellen Segments wählen (liefert stets ausgewogene Teillisten, erfordert jedoch einen aufwändigeren Implementierungsansatz)

Lass uns den Algorithmus an einigen Beispielen durchspielen:
[4, 1, -1, 0, 2, 8]
  1. quicksort(a, 0, 5) → pivot = 4 [4, 1, -1, 0, 2, 8]
    1. l=1, r=5a[l] = 1 < pivot ⇒ l += 1
    2. l=2, r=5a[l] = -1 < pivot ⇒ l += 1
    3. l=3, r=5a[l] = 0 < pivot ⇒ l += 1
    4. l=4, r=5a[l] = 2 < pivot ⇒ l += 1
    5. l=5, r=5a[l] = 8 ≥ pivot ⇒ swap a[l] and a[r], r -= 1
    6. swap a[start] and a[r][2, 1, -1, 0, 4, 8]
    7. quicksort(a, 0, 3) and quicksort(a, 5, 5)
  1. quicksort(a, 0, 3) → pivot = 2 [2, 1, -1, 0, 4, 8]
    1. l=1, r=3a[l] = 1 < pivot ⇒ l += 1
    2. l=2, r=3a[l] = -1 < pivot ⇒ l += 1
    3. l=3, r=3a[l] = 0 < pivot ⇒ l += 1
    4. swap a[start] and a[r][0, 1, -1, 2, 4, 8]
    5. quicksort(a, 0, 2) and quicksort(a, 3, 3)
  1. quicksort(a, 0, 2) → pivot = 0 [0, 1, -1, 2, 4, 8]
    1. l=1, r=2a[l] = 1 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [0, -1, 1, 2, 4, 8]
    2. l=1, r=1a[l] = -1 < pivot ⇒ l += 1
    3. swap a[start] and a[r][-1, 0, 1, 2, 4, 8]
    4. quicksort(a, 0, 0) and quicksort(a, 2, 2)
  1. [-1, 0, 1, 2, 4, 8]
[4, 5, 3, 4, 4, 8, 4, 1, 2, 9, 7, 4, -1]
  1. quicksort(a, 0, 12) → pivot = 4 [4, 5, 3, 4, 4, 8, 4, 1, 2, 9, 7, 4, -1]
    1. l=1, r=12a[l] = 5 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, 5, 3, 4, 4, 8, 4, 1, 2, 9, 7, 4, -1]
    2. l=1, r=11a[l] = -1 < pivot ⇒ l += 1
    3. l=2, r=11a[l] = 3 < pivot ⇒ l += 1
    4. l=3, r=11a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, -1, 3, 4, 4, 8, 4, 1, 2, 9, 7, 4, 5]
    5. l=3, r=10a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, -1, 3, 4, 4, 8, 4, 1, 2, 9, 7, 4, 5]
    6. l=3, r=9a[l] = 7 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, -1, 3, 7, 4, 8, 4, 1, 2, 9, 4, 4, 5]
    7. l=3, r=8a[l] = 9 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, -1, 3, 9, 4, 8, 4, 1, 2, 7, 4, 4, 5]
    8. l=3, r=7a[l] = 2 < pivot ⇒ l += 1
    9. l=4, r=7a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, -1, 3, 2, 4, 8, 4, 1, 9, 7, 4, 4, 5]
    10. l=4, r=6a[l] = 1 < pivot ⇒ l += 1
    11. l=5, r=6a[l] = 8 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, -1, 3, 2, 1, 8, 4, 4, 9, 7, 4, 4, 5]
    12. l=5, r=5a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [4, -1, 3, 2, 1, 4, 8, 4, 9, 7, 4, 4, 5]
    13. swap a[start] and a[r][1, -1, 3, 2, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    14. quicksort(a, 0, 3) and quicksort(a, 5, 12)
  1. quicksort(a, 0, 3) → pivot = 1 [1, -1, 3, 2, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    1. l=1, r=3a[l] = -1 < pivot ⇒ l += 1
    2. l=2, r=3a[l] = 3 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [1, -1, 3, 2, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    3. l=2, r=2a[l] = 2 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [1, -1, 2, 3, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    4. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    5. quicksort(a, 0, 0) and quicksort(a, 2, 3)
  1. quicksort(a, 2, 3) → pivot = 2 [-1, 1, 2, 3, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    1. l=3, r=3a[l] = 3 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    2. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    3. quicksort(a, 2, 1) and quicksort(a, 3, 3)
  1. quicksort(a, 5, 12) → pivot = 4 [-1, 1, 2, 3, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    1. l=6, r=12a[l] = 8 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 8, 4, 9, 7, 4, 4, 5]
    2. l=6, r=11a[l] = 5 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 5, 4, 9, 7, 4, 4, 8]
    3. l=6, r=10a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 4, 9, 7, 4, 5, 8]
    4. l=6, r=9a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 4, 9, 7, 4, 5, 8]
    5. l=6, r=8a[l] = 7 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 7, 4, 9, 4, 4, 5, 8]
    6. l=6, r=7a[l] = 9 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 9, 4, 7, 4, 4, 5, 8]
    7. l=6, r=6a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 9, 7, 4, 4, 5, 8]
    8. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 4, 9, 7, 4, 4, 5, 8]
    9. quicksort(a, 5, 4) and quicksort(a, 6, 12)
  1. quicksort(a, 6, 12) → pivot = 4 [-1, 1, 2, 3, 4, 4, 4, 9, 7, 4, 4, 5, 8]
    1. l=7, r=12a[l] = 9 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 9, 7, 4, 4, 5, 8]
    2. l=7, r=11a[l] = 8 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 8, 7, 4, 4, 5, 9]
    3. l=7, r=10a[l] = 5 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 5, 7, 4, 4, 8, 9]
    4. l=7, r=9a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 4, 7, 4, 5, 8, 9]
    5. l=7, r=8a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 4, 7, 4, 5, 8, 9]
    6. l=7, r=7a[l] = 7 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 7, 4, 4, 5, 8, 9]
    7. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 4, 7, 4, 4, 5, 8, 9]
    8. quicksort(a, 6, 5) and quicksort(a, 7, 12)
  1. quicksort(a, 7, 12) → pivot = 7 [-1, 1, 2, 3, 4, 4, 4, 7, 4, 4, 5, 8, 9]
    1. l=8, r=12a[l] = 4 < pivot ⇒ l += 1
    2. l=9, r=12a[l] = 4 < pivot ⇒ l += 1
    3. l=10, r=12a[l] = 5 < pivot ⇒ l += 1
    4. l=11, r=12a[l] = 8 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 7, 4, 4, 5, 8, 9]
    5. l=11, r=11a[l] = 9 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 7, 4, 4, 5, 9, 8]
    6. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 4, 5, 4, 4, 7, 9, 8]
    7. quicksort(a, 7, 9) and quicksort(a, 11, 12)
  1. quicksort(a, 7, 9) → pivot = 5 [-1, 1, 2, 3, 4, 4, 4, 5, 4, 4, 7, 9, 8]
    1. l=8, r=9a[l] = 4 < pivot ⇒ l += 1
    2. l=9, r=9a[l] = 4 < pivot ⇒ l += 1
    3. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 4, 4, 4, 5, 7, 9, 8]
    4. quicksort(a, 7, 8) and quicksort(a, 10, 9)
  1. quicksort(a, 7, 8) → pivot = 4 [-1, 1, 2, 3, 4, 4, 4, 4, 4, 5, 7, 9, 8]
    1. l=8, r=8a[l] = 4 ≥ pivot ⇒ swap a[l] and a[r], r -= 1 [-1, 1, 2, 3, 4, 4, 4, 4, 4, 5, 7, 9, 8]
    2. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 4, 4, 4, 5, 7, 9, 8]
    3. quicksort(a, 7, 6) and quicksort(a, 8, 8)
  1. quicksort(a, 11, 12) → pivot = 9 [-1, 1, 2, 3, 4, 4, 4, 4, 4, 5, 7, 9, 8]
    1. l=12, r=12a[l] = 8 < pivot ⇒ l += 1
    2. swap a[start] and a[r][-1, 1, 2, 3, 4, 4, 4, 4, 4, 5, 7, 8, 9]
    3. quicksort(a, 11, 11) and quicksort(a, 13, 12)
  1. [-1, 1, 2, 3, 4, 4, 4, 4, 4, 5, 7, 8, 9]
Die durchschnittliche Laufzeit des QuickSort-Algorithmus beträgt . Je nach Wahl des Pivot-Elements kann der Algorithmus jedoch auch im schlechtesten Fall in enden.
🤔 Hast du eine Idee, bei welchem Beispiel der Algorithmus Operationen ausführen würde, wenn man immer start als Pivot nimmt?

Herausforderung

Gegeben eine Liste von n ganzen Zahlen und q Pivots, sollst du für jeden Pivot alle Elemente, die kleiner als das Pivot sind, nach links verschieben und alle, die größer als das Pivot sind, nach rechts. Die Werte, die dem Pivot entsprechen, sollen zusammenhängend bleiben (sie gehören rechts von den kleineren und links von den größeren Zahlen).

Eingabe

Die erste Zeile der Eingabe enthält eine einzelne ganze Zahl n (1 ≤ n ≤ 100 000).
Die nächste Zeile enthält eine Liste von n durch Leerzeichen getrennten ganzen Zahlen ().
Die dritte Zeile enthält eine einzelne ganze Zahl q (1 ≤ q ≤ 10).
Die nächste Zeile enthält eine Liste von n durch Leerzeichen getrennten ganzen Zahlen (1 ≤ ≤ n) für die Indices der Pivot-Elemente.

Ausgabe

Für jedes der q Pivots soll das Programm das Ergebnisarray nach der entsprechenden Umordnung ausgeben. Wenn es mehrere mögliche richtige Antworten gibt, darf das Programm eine davon ausgeben.

Beispiele

Eingabe
Ausgabe
7 1 8 0 3 4 -2 4 3 4 2 5
1 0 -2 3 4 4 8 -2 0 1 3 4 4 8 -2 0 1 3 4 4 8
 

Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 10 MB

To check your solution you need to sign in
Sign in to continue