Ich brauche eine Datenstruktur, die immer die n
größten Elemente enthält, die bisher eingefügt wurden (in keiner bestimmten Reihenfolge).
Wenn also n
3 ist, könnten wir die folgende Sitzung haben, in der ich einige Zahlen einfüge und den Inhalt des Containers ändert:
Sie bekommen die Idee. Wie heißt die Datenstruktur? Was ist der beste Weg dies zu implementieren? Oder ist das in einer Bibliothek?
Ich denke, einen Container mit einem priority_queue
für seine Elemente (Delegierung) zu verwenden, der den umgekehrten Vergleich verwendet, so dass pop
das kleinste Element entfernt. Die Funktion insert
prüft zuerst, ob das neue einzufügende Element größer als das kleinste Element ist. Wenn das der Fall ist, werfen wir das kleinste heraus und drücken das neue Element.
(Ich habe eine C++
Implementierung im Hinterkopf, aber die Frage ist trotzdem sprachunabhängig.)
Die gewünschte Datenstruktur ist wahrscheinlich der implizite Heap . Die rohe Datenstruktur ist nur ein Array; Nennen Sie für die Bequemlichkeit, dass es N = 2 ^ n Elemente in der Größe ist, und dass Sie die größten N-1 Elemente beibehalten möchten.
Die Idee ist, das Array (nennen wir es A) als kompletten binären Baum der Tiefe n zu behandeln:
Um den Baum als "Heap" zu erhalten, müssen Sie sicherstellen, dass jeder Knoten kleiner als (oder gleich) seinen Kindern ist. Dies wird "Heap-Bedingung" genannt:
So verwenden Sie den Heap, um die größten N-Elemente zu verwalten:
Im Grunde wird jedes Ersatzelement den Baum "filtern", bis er seinen natürlichen Platz erreicht hat. Dies wird höchstens n = log2 (N) Schritte dauern, was so gut wie möglich ist. Außerdem ermöglicht die implizite Form des Baums eine sehr schnelle Implementierung; Bestehende Bibliotheken mit eingeschränkter Priorität werden höchstwahrscheinlich einen impliziten Heap verwenden.
Eine Prioritätswarteschlange ist in C ++ mit STL am nächsten. Sie könnten es in eine andere Klasse einfügen, um eine eigene Implementierung zu erstellen, die die Größe automatisch anpasst.
Sprach-agnostisch (obwohl vielleicht nicht Speicher-Fragmentierung-sicher):
std :: priority_queue macht Schritt 2 für Sie.
In Java können Sie ein SortedSet verwenden, das z. von einem TreeSet. Prüfen Sie nach jedem Einfügen, ob die Menge zu groß ist. Wenn ja, entfernen Sie das letzte Element.
Dies ist einigermaßen effizient, ich habe es erfolgreich für die Lösung mehrerer Project Euler-Probleme verwendet.
Eine beschränkte Prioritätswarteschlange , denke ich ... Java hat so etwas in seiner Standardbibliothek. BEARBEITEN : Es heißt LinkedBlockingQueue
. Ich bin mir nicht sicher, ob die C ++ STL etwas ähnliches enthält.
Ja, Sie können einen minimalen Kopf der Größe N beibehalten Dann vergleichen Sie das neue Element mit dem Stammelement bei jedem Einfügen Pop die Wurzel und fügen Sie das Element ein, wenn es "größer" als die Wurzel ist Schließlich enden Sie mit N größten Items
Erstellen Sie einen Min-Heap, speichern Sie auch einen Zähler.
Immer wenn der Zähler erreicht ist; Extrakt-min.
Sie können dies tun in: O (1) einfügen, get-min und O (log log n) extract-min. [1]
Alternativ können Sie dies mit O (log n) einfügen und O (1) für die anderen erwähnten Operationen. [2]
[1]
M. Thorup, "Integer-Prioritätswarteschlangen mit Verkleinerungsschlüssel in konstanter Zeit und das Problem mit den kürzesten Wegen der einzelnen Quelle", in Proceedings des fünfunddreißigsten jährlichen ACM-Symposiums über Theory of Computing, New York, NY, USA , 2003, S. 149-158.
Tags und Links language-agnostic data-structures priority-queue