Finden running median aus einem stream von ganzen zahlen
Mögliche Duplikate:
Rolling-median-Algorithmus in C
Gegeben, dass ganze zahlen sind, Lesen aus einem Datenstrom. Finden median der Elemente Lesen so weit in effizienter Weise.
Lösung, die ich gelesen habe: Wir können ein max-heap auf der linken Seite zu repräsentieren Elemente, die kleiner sind als der effektive Mittelwert (median), und ein min-heap auf der rechten Seite zur Darstellung von Elementen, die größer sind als der effektive Mittelwert.
Nach der Verarbeitung einer eingehenden element, die Anzahl der Elemente in den heaps unterscheiden sich höchstens um 1 element. Wenn beide Haufen enthalten die gleiche Anzahl von Elementen, finden wir den Durchschnitt heap Stamm-Daten als effektive median. Wenn der Haufen nicht ausgeglichen sind, wählen wir die effektive median von der Wurzel des heap-enthält mehr Elemente.
Aber wie würden wir konstruieren ein max-heap und min-heap, d.h. wie würden wir wissen, die effektive median hier? Ich glaube, wir würden Sie 1 ein element in max-heap und dann die nächsten 1-element in min-heap, und so weiter für alle Elemente. Korrigieren Sie mich, Wenn ich falsch bin hier.
- Clevere Algorithmus, mit Haufen. Aus dem Titel konnte ich nicht sofort denken Sie an eine Lösung.
- Wesir Lösung, sieht gut aus für mich, außer, dass ich war der Annahme (wenn Sie nicht zum Staat), dass dieser Strom kann beliebig lang sein, so dass Sie konnte nicht alles behalten im Gedächtnis. Ist das der Fall?
- Für beliebig lange streams, kann man den Mittelwert der letzten N Elemente durch die Verwendung von Fibonacci-heaps (Sie erhalten also log(N) löscht) und die Speicherung von Zeigern auf Elemente eingefügt, um (in z.B. ein deque), dann entfernen Sie die älteste element bei jedem Schritt, wenn der Haufen voll sind (vielleicht auch an beweglichen Sachen von einem Haufen auf den anderen). Sie könnten etwas besser als N durch das speichern der Anzahl von wiederholten Elementen (bei vielen Wiederholungen), aber im Allgemeinen, ich denke, Sie haben eine Art von Verteilungsgerechtigkeit Annahmen, wenn Sie möchten, dass der median für den gesamten Strom.
- Sie können beginnen, mit beiden heaps leer. Erste int geht auf einen Haufen; das zweite geht entweder in die andere, oder bewegen Sie den ersten Artikel in den anderen Haufen und dann einfügen. Dieser Satz verallgemeinert auf "nicht erlauben einen heap zu gehen größer ist als der andere +1" und keine speziellen Gehäuse erforderlich ist (die "root-Wert" eines leeren heap kann definiert werden als 0)
- NUR ich habe diese Frage auf einem MSFT-interview. Vielen Dank für die Buchung
- Wieder geöffnet, da die vorgeschlagene doppelte ist zu Fragen, die speziell für eine effiziente Umsetzung, und es geht mehr um die Allgemeine Vorgehensweise. Auch top-stimmten Antwort hier hat weit über zehn mal die Punktzahl des top-stimmten Antwort auf die doppelte, was bedeutet, dass, wenn überhaupt, die anderen posten sollten die sein, die geschlossen werden sollte, oder die Beiträge, die zusammengeführt werden sollen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es eine Reihe von verschiedenen Lösungen für die Suche nach running median von gestreamten Daten, werde ich kurz darüber sprechen, ganz am Ende der Antwort.
Die Frage ist, über die details der eine bestimmte Lösung (max-heap/min-heap-Lösung), und wie heap-basierte Lösung funktioniert, ist unten erklärt:
Für die ersten beiden Elemente hinzufügen kleineres zum maxHeap auf der linken Seite, und der größere zu der minHeap auf der rechten Seite. Dann den Prozess Strom-Daten eins nach dem anderen,
Dann zu einem gegebenen Zeitpunkt können Sie berechnen den median so:
Jetzt werde ich sprechen über das problem im Allgemeinen, wie versprochen, die Antwort beginnt. Suche nach running median aus einem Strom von Daten ist ein schwieriges problem, und der Suche nach einem genau die Lösung, die mit Speicher-Einschränkungen effizient ist wahrscheinlich unmöglich für den Allgemeinen Fall. Auf der anderen Seite, wenn die Daten hat einige Eigenschaften, die wir ausnutzen können, entwickeln wir für Sie effiziente Lösungen spezialisiert. Zum Beispiel, wenn wir wissen, dass die Daten ist ein integraler Typ ist, dann können wir zählen, Sortieren, das kann Ihnen eine ständige Erinnerung Konstante Zeit-Algorithmus. Heap-basierten Lösung ist eine Allgemeine Lösung, weil es kann verwendet werden, für andere Datentypen (Double) als gut. Und schließlich, wenn der genaue median ist nicht erforderlich und eine Angleichung genug ist, können Sie nur versuchen, Schätzung einer Wahrscheinlichkeits-Dichte-Funktion für die Daten und Schätzung median benutzen.
Wenn Sie nicht halten kann alle Elemente im Arbeitsspeicher auf einmal, wird dieses problem sehr viel schwieriger. Die heap-Lösung erfordert, dass Sie halten alle Elemente, die im Speicher auf einmal. Dies ist nicht möglich in den meisten realen Anwendungen dieses Problems.
Statt, wie Sie sehen, zahlen, behalten Sie die zählen von der Anzahl der Zeiten, die Sie sehen, jede ganze Zahl. Vorausgesetzt, 4-byte-Ganzzahlen, die 2^32 Eimer, oder höchstens 2^33 ganze zahlen (Schlüssel und die Anzahl für jede int), die 2^35 bytes oder 32 GB. Es wird wahrscheinlich viel weniger als dies, weil Sie nicht brauchen, um zu speichern die Taste oder, zählen für jene Einträge, die von 0 (dh. wie ein defaultdict in python). Dies benötigt Konstante Zeit zum einlegen jeder neuen integer.
Dann an einem beliebigen Punkt zu finden, der median, verwenden Sie einfach die Grafen zu bestimmen, welche ganze Zahl ist das mittlere element. Dies benötigt Konstante Zeit (wenn auch eine große Konstante, aber dennoch konstant).
Wenn die Varianz der Eingang ist statistisch verteilt (z.B. normal -, log-normal ... usw) dann reservoir sampling ist eine sinnvolle Schätzung der Perzentile/Mediane aus einer beliebig langen Strom von zahlen.
"reservoir" ist dann ein Lauf, gleichmäßige (gerechte), die Probe von allen Eingangs - unabhängig von der Größe. Das finden der median (oder jedem Perzentil) ist dann ein straight-forward Angelegenheit der Sortierung der Stausee und der Abruf der interessante Punkt.
Da das reservoir ist mit fester Größe, der Art angesehen werden können, effektiv O(1) - und diese Methode wird ausgeführt, sowohl mit konstanter Zeit-und Speicherbedarf.
Den effizientesten Weg berechnen einen prozentualen einen stream, den ich gefunden habe, ist der P2-Algorithmus: Raj Jain, Imrich Chlamtac: Die P2-Algorithmus für die Dynamische Berechnung von Quantiiles und Histogramme Ohne die Speicherung der Beobachtungen. Commun. ACM 28(10): 1076-1085 (1985)
Der Algorithmus ist einfach zu implementieren und funktioniert sehr gut. Es ist eine Schätzung, die allerdings, so man im Hinterkopf behalten. Aus dem abstract:
Dieses problem hat eine exakte Lösung, muss nur die n zuletzt gesehen Elemente werden im Speicher gehalten. Es ist schnell und skaliert gut.
Einer Wende skiplist unterstützt O(ln n) - einfügen, entfernen, und die indizierte Suche von beliebigen Elementen, während die Aufrechterhaltung der sortierten Reihenfolge. Wenn gepaart mit einem FIFO-Warteschlange, dass die tracks, die n-te ältesten Eintrag, die Lösung ist einfach:
Hier sind die links zu den kompletten funktionierenden code (ein einfach-zu-verstehen-Klasse-version und eine optimierte generator-version mit der Wende skiplist-code inlined):
http://code.activestate.com/recipes/576930-efficient-running-median-using-an-indexable-skipli/
http://code.activestate.com/recipes/577073 .
Einer intuitiven Weg, um darüber nachzudenken ist, dass, wenn Sie hatte einen vollen ausgeglichenen binären Suchbaum, dann die Wurzel wäre das median-element, da es die gleiche Anzahl von kleineren und größeren Elementen.
Nun, wenn der Baum nicht voll ist dies nicht ganz der Fall sein, da es Elemente fehlen aus der letzten Ebene.
Also, was können wir stattdessen tun haben, ist der median, und zwei symmetrische binäre Bäume, einer für Elemente, die kleiner als der median, und eine für Elemente, die größer als der median. Die beiden Bäume müssen gehalten werden, in der gleichen Größe.
Wenn wir einen neuen integer aus dem Datenstrom, vergleichen wir es auf den median. Wenn er größer ist als der median, die wir hinzufügen, um den richtigen Baum. Wenn die beiden Baum-Größen unterscheiden sich um mehr als 1, nehmen wir die min element im rechten Baum, machen es die neuen median, und das alte median im linken Baum. Ähnlich wie für kleinere.
Effiziente, ist ein Wort, das abhängig vom Kontext. Die Lösung für dieses problem hängt von der Anzahl der Anfragen erfolgt im Vergleich zu der Menge von Einfügungen. Angenommen, Sie sind das einfügen von N zahlen und K-mal gegen Ende waren Sie interessiert an den median. Die heap-basierten Algorithmus die Komplexität wäre O(N log N + K).
Betrachten Sie die folgende alternative. Zupfen Sie die zahlen in ein array, und für jede Abfrage, ausführen der linear-Auswahl-Algorithmus (unter Verwendung des quicksort-pivot, sagen). Jetzt haben Sie einen Algorithmus mit Laufzeit O(K N).
Nun, wenn K hinreichend klein ist (seltene Abfragen), letzterer Algorithmus ist effizienter und Umgekehrt.
Können nicht dies tun Sie mit nur einem heap? Update: nicht. Siehe auch den Kommentar.
Invariante: Nach dem Lesen
2*n
Eingänge, die min-heap enthält dien
größte von Ihnen.Schleife: Lesen, 2 Eingänge. Fügen Sie beide auf dem heap, und entfernen Sie die heap min. Diese wieder her, die invariant.
So, wenn
2n
Eingänge, die gelesen wurden, die heap min ist die N-te größte. Es müssen ein wenig zusätzliche Komplikation, den Durchschnitt der zwei Elemente rund um die median-position und zu behandeln Abfragen, nachdem eine ungerade Anzahl von Eingängen.