Median in O(n log n) finden
- Die einfachste Methode ist, die Liste zu sortieren und dann den Median auszuwählen
- Vergleichsbasiertes Sortieren hat eine Zeitkomplexität von
O(n log n) - Codebeispiel:
def nlogn_median(l): l = sorted(l) if len(l) % 2 == 1: return l[len(l) // 2] else: return 0.5 * (l[len(l) // 2 - 1] + l[len(l) // 2])
Median in durchschnittlich O(n) finden
-
Mit dem Algorithmus "quickselect" lässt sich der Median im Durchschnitt in linearer Zeit finden
-
Ein rekursiver Algorithmus, entwickelt von Tony Hoare
-
Ablauf:
- Wähle einen beliebigen Index aus der Liste und setze ihn als Pivot
- Teile die Liste anhand des Pivot in zwei Gruppen:
- Elemente, die kleiner oder gleich dem Pivot sind
- Elemente, die größer als der Pivot sind
- Durchsuche rekursiv die Gruppe, die den Median enthält
-
Codebeispiel:
import random def quickselect_median(l, pivot_fn=random.choice): if len(l) % 2 == 1: return quickselect(l, len(l) // 2, pivot_fn) else: return 0.5 * (quickselect(l, len(l) // 2 - 1, pivot_fn) + quickselect(l, len(l) // 2, pivot_fn)) def quickselect(l, k, pivot_fn): if len(l) == 1: assert k == 0 return l[0] pivot = pivot_fn(l) lows = [el for el in l if el < pivot] highs = [el for el in l if el > pivot] pivots = [el for el in l if el == pivot] if k < len(lows): return quickselect(lows, k, pivot_fn) elif k < len(lows) + len(pivots): return pivots[0] else: return quickselect(highs, k - len(lows) - len(pivots), pivot_fn)
Beweis für durchschnittlich O(n)
- Wenn der Pivot die Liste ungefähr halbiert, arbeitet jeder rekursive Aufruf auf der Hälfte der Daten des vorherigen Schritts
- Mathematischer Beweis:
C = n + n/2 + n/4 + n/8 + ... = 2n = O(n)
Deterministisches O(n)
-
Garantiert lineare Zeit auch im Worst Case
-
Verwendet den Algorithmus "median-of-medians" zur Auswahl des Pivot
-
Ablauf:
- Teile die Liste in Gruppen zu je 5 Elementen
- Sortiere jede Gruppe und wähle den Median
- Wähle den Median der Mediane als Pivot
-
Codebeispiel:
def pick_pivot(l): assert len(l) > 0 if len(l) < 5: return nlogn_median(l) chunks = chunked(l, 5) full_chunks = [chunk for chunk in chunks if len(chunk) == 5] sorted_groups = [sorted(chunk) for chunk in full_chunks] medians = [chunk[2] for chunk in sorted_groups] median_of_medians = quickselect_median(medians, pick_pivot) return median_of_medians def chunked(l, chunk_size): return [l[i:i + chunk_size] for i in range(0, len(l), chunk_size)]
Zusammenfassung
- Der quickselect-Algorithmus kann bei geeigneter Pivot-Wahl den Median in linearer Zeit finden
- Der median-of-medians-Algorithmus ist eine Methode zur Pivot-Auswahl, die auch im Worst Case lineare Zeit garantiert
- In der Praxis ist die zufällige Pivot-Wahl meist ausreichend effektiv
Zusammenfassung von GN⁺
- Dieser Artikel erklärt verschiedene Algorithmen zur Bestimmung des Medians und behandelt insbesondere Methoden, den Median in linearer Zeit zu finden
- Der quickselect-Algorithmus ist im Durchschnitt schnell, aber für den Worst Case kann der median-of-medians-Algorithmus verwendet werden
- In praktischen Anwendungen ist die zufällige Pivot-Wahl in den meisten Fällen ausreichend effektiv
- Ein Algorithmus mit ähnlicher Funktion ist introselect, der in der C++-Standardbibliothek verwendet wird
1 Kommentare
Hacker-News-Kommentare