Sie können das i-te Element aus einem Haufen entfernen ganz einfach:
h[i] = h[-1]
h.pop()
heapq.heapify(h)
einfach das Element, das Sie mit dem letzten Element entfernen möchten, ersetzen und das letzte Element entfernen Sie dann den Haufen wieder heapify. Das ist O (n), wenn Sie möchten, können Sie dasselbe in O tun (log (n)), aber Sie müssen einige der internen Heapify-Funktionen aufrufen, oder besser, wie larsmans darauf hingewiesen hat, kopieren Sie einfach die Quelle von _siftup/_siftdown aus heapq.py in Ihren eigenen Code:
h[i] = h[-1]
h.pop()
if i < len(h):
heapq._siftup(h, i)
heapq._siftdown(h, 0, i)
Beachten Sie, dass Sie in jedem Fall nicht nur tun h[i] = h.pop()
wie das wäre, wenn i
Referenzen das letzte Element scheitern. Wenn Sie im Spezialfall das letzte Element entfernen, können Sie das Überschreiben und Pop kombinieren.
Beachten Sie, dass die typische Größe des Heap je finden Sie vielleicht, dass nur heapify
Aufruf während theoretisch weniger effizient schneller sein könnte als die Wiederverwendung von _siftup
/_siftdown
: ein wenig Selbstbeobachtung wird zeigen, dass heapify
wahrscheinlich in C implementiert ist, aber die C-Implementierung der internen Funktionen sind nicht offengelegt. Wenn Ihnen die Leistung wichtig ist, sollten Sie einige Zeittests an typischen Daten durchführen, um zu sehen, welche die beste ist. Wenn Sie nicht wirklich massive Haufen haben, ist Big-O vielleicht nicht der wichtigste Faktor.
Edit: jemand versucht, diese Antwort zu bearbeiten, den Anruf zu _siftdown
mit einem Kommentar zu entfernen, dass:
_siftdown nicht benötigt wird. New h [i] ist garantiert das kleinste Kind der alten h [i], das immer noch größer ist als das Elternteil des alten h [i] (neues Elternteil von h [i]). _Settdown wird ein No-Op sein. Ich muss bearbeiten, da ich nicht genug rep haben, um einen Kommentar noch hinzuzufügen.
Was sie in diesem Kommentar verpasst haben, ist, dass h[-1]
kein Kind von h[i]
überhaupt sein könnte. Der neue Wert, der bei h[i]
eingefügt wird, könnte von einem völlig anderen Zweig des Heaps kommen, so dass er in beide Richtungen gesiebt werden müsste.
auch auf den Kommentar zu fragen, warum gerade nicht sort()
verwenden, um die Haufen wiederherzustellen: Aufruf _siftup
und _siftdown
sind beide O-Operationen (n log), heapify Aufruf ist O (n).Der Aufruf von sort()
ist eine Operation O (n log n). Es ist durchaus möglich, dass Calling Sort schnell genug ist, aber für große Haufen ist es ein unnötiger Overhead.
Bearbeitet um das von @Seth Bruder aufgezeigte Problem zu vermeiden. Wenn i
auf das Endelement verweist, würde der Aufruf _siftup()
fehlschlagen, aber in diesem Fall bricht ein Element am Ende des Heapspeichers die Heap-Invariante nicht.
+1, mit der Randnotiz, dass es sauberer wäre, die Definition von '_siftup' in das Programm zu kopieren, wie von @AlexMartelli empfohlen, [hier] (http://stackoverflow.com/questions/1465662/how-can- i-implementieren-verringern-Taste-Funktionalität-in-Pythons-heapq). –
Danke, '_siftup' sieht definitiv interessant aus! Btw., Warum 'pop (-1)', anstatt nur 'pop()'? –
@EcirHana nur, weil ich mich nicht an den Standard von meinem Kopf erinnern kann. Ich habe es aufgeräumt. – Duncan