[GO] Ich möchte eine Prioritätswarteschlange erstellen, die mit Python (2.7) aktualisiert werden kann.

Überblick

Erstellen und spielen Sie mit Prioritätswarteschlangen, mit denen Elemente aktualisiert werden können. Um genau zu sein, wird durch das Verschieben desselben Elements mit unterschiedlichen Prioritäten eine priorisierte Warteschlange erstellt, die die Prioritäten überschreibt.

Zusammenfassung

Aufgrund der Kurzreferenz zum Algorithmus musste ich eine Prioritätswarteschlange verwenden, suchte jedoch nach "Prioritätswarteschlange Python" und sie wird oben angezeigt. http://docs.python.jp/2/library/heapq.html Als ich es mir ansah, sagte es etwas Schreckliches.

Prioritätswarteschlangen sind eine häufige Verwendung von Heaps und haben einige Schwierigkeiten bei der Implementierung:

  • Sortierstabilität: Wie können zwei Aufgaben mit gleicher Priorität in der Reihenfolge zurückgegeben werden, in der sie ursprünglich hinzugefügt wurden?

Die Lösung für die ersten beiden Schwierigkeiten besteht darin, den Artikel als Liste mit drei Elementen zu speichern, die die Priorität, die Artikelnummer und die Aufgabe enthält. Diese Artikelnummer dient als Verbindungsunterbrechung, um sicherzustellen, dass zwei Aufgaben mit derselben Priorität in der Reihenfolge zurückgegeben werden, in der sie hinzugefügt wurden. Und da die beiden Artikelnummern niemals gleich sind, kann der Tapple-Vergleich nicht versuchen, die beiden Aufgaben direkt zu vergleichen. Die verbleibende Schwierigkeit besteht hauptsächlich darin, offene Aufgaben zu finden, ihre Prioritäten zu ändern oder sie ganz zu entfernen. Das Finden einer Aufgabe erfolgt durch ein Wörterbuch, das auf Elemente in der Warteschlange verweist. Das Löschen von Elementen oder das Ändern ihrer Prioritäten ist schwieriger, da dadurch die unveränderlichen Beziehungen der Heap-Struktur unterbrochen werden. Eine mögliche Lösung besteht darin, das Element als ungültig zu markieren und das geänderte Prioritätselement bei Bedarf hinzuzufügen:

Nun, ich weiß was du sagst. Ich habe mich gefragt, ob Python standardmäßig keine Prioritätswarteschlangen bereitstellt, da heapq so etwas sagt. Dies ist jedoch nicht der Fall, und es gibt eine ordnungsgemäße Queue.PriorityQueue (). Obwohl dies der Fall ist, scheint es nicht möglich zu sein, den Aktualisierungsprozess mit dieser PriorityQueue () sofort durchzuführen. In Anbetracht dessen, was auf dieser Seite geschrieben steht, war ich neugierig, um wie viel die Berechnungsgeschwindigkeit besser oder schlechter sein würde ~~ es ist mir egal ~~.

Design

Eine Warteschlange mit handgefertigten Prioritäten (im Folgenden als "Handwarteschlange" bezeichnet) besteht aus einer Liste von Tapples (sortkey (Wert, Generation)) und einem Wörterbuch, das für jeden Wert eine Generation enthält. Das Löschen ist ein Bild, das nicht wie oben beschrieben ausgeführt wird, sondern durch Markieren ausgeführt wird. Es wird jedoch gesteuert, indem die Nummer der neuesten Generation im Wörterbuch gespeichert und nicht die neuesten Daten verwendet werden. Ich werde. Da sich die Suchleistung verschlechtert, wenn Elemente akkumuliert werden, muss außerdem die Datenlöschung + Heap-Rekonstruktion auf eine Garbage Collection-Weise durchgeführt werden. In Bezug auf den Zeitpunkt der "Speicherbereinigung" hier habe ich beschlossen, sie als geeignete Konstante m beizubehalten und zu rekonstruieren, wenn die Anzahl der Elemente (die Anzahl der äußersten Klammern des Taples, die als 1 gezählt werden) m überschreitet. Und so weiter.

--push → heapq.heappush (), um das Wörterbuch zu aktualisieren. Wenn die Größe m überschreitet, wird der Heap nur mit der neuesten Generation erneut erstellt. * Da die Wörterbuchgenerierung aktualisiert wird, dient sie auch als Änderung. --pop → nimm weiterhin heapq.heappop (), bis die neueste Generation herausgenommen wird (Generierung aus dem Wörterbuch basierend auf dem Wert extrahieren und heappop () wiederholen, wenn sie nicht übereinstimmen) - * löschen → Nur Wörterbuch aktualisieren Mach es zum Wind. Der zufällige Zugriff auf die Elemente der Warteschlange ist uns derzeit egal. Wenn Sie dem Wörterbuch einen Wert geben, wird mehr Speicher benötigt, aber theoretisch können Sie zufällig darauf zugreifen. Implementierung

TeQueue.py


import heapq
def tepush(l, d, m, sortkey, value):
    if not value in d:
        generation = 1
    else:
        generation = d[value] + 1
    d[value] = generation
    heapq.heappush(l, (sortkey, value, generation))
    length = len(l)
    if length > m: #Den Haufen rekonstruieren
        lt = []
        for n in range(0,length):
            if l[n][2] == d[l[n][1]]:
                heapq.heappush(lt, (l[n][0], l[n][1], 1))
                d[l[n][1]] = 1
        return lt
    else:
        return l

def tepop(l, d):
    while len(l) > 0:
        (sortkey, value, generation) = heapq.heappop(l)
        if d[value] == generation:
            return (sortkey, value, generation) 

Dies ermöglicht es, den Wert zu "überschreiben", der dem gleichen Wert entspricht, der im Entwurf beschrieben ist.

Vergleich mit anderen Warteschlangen

Vergleiche mit Queue.PriorityQueue ().

Initialisieren

Führen Sie vorerst die folgende Initialisierung durch.

initialize.py


#Erzeugen Sie eine zufällige Folge von N.
import random
N = 100000
M = 100000
target = range(0,N)
temp = range(0,N)
for n in range(N-1,-1,-1):
  target[n] = temp.pop(random.randint(0,n))

push

pushtest.py


import Queue
import heapq
import datetime

d = datetime.datetime(1,1,1)
time1 = d.now()
t = Queue.PriorityQueue(N)
for n in range(0,N):
    t.put((target[n], n))
time2 = d.now()
u = []
for n in range(0,N):
    heapq.heappush(u, (target[n], n))
time3 = d.now()
v = []
dd = {}
for n in range(0,N):
    v = tepush(v, dd, 2*M, target[n], n)
time4 = d.now()
print('push:Queue',(time2 - time1).__str__())
print('push:Heap',(time3 - time2).__str__())
print('push:TeQ',(time4 - time3).__str__())

Ergebnis drücken


('push:Queue', '0:00:00.350000')
('push:Heap', '0:00:00.086000')
('push:TeQ', '0:00:00.137000')

Es sieht aus wie das. TeQ> Heap, weil es viele Vergleiche gibt, aber es ist viel schneller als Queue.

pop

poptest.py


import Queue
import heapq
import datetime

time1 = d.now()
for n in range(0,M):
    t.get()
time2 = d.now()
for n in range(0,M):
    heapq.heappop(u)
time3 = d.now()
for n in range(0,M):
    tepop(v, dd)
time4 = d.now()
print('pop:Queue',(time2 - time1).__str__())
print('pop:Heap',(time3 - time2).__str__())
print('pop:TeQ',(time4 - time3).__str__())

Pop-Ergebnis


('pop:Queue', '0:00:00.484000')
('pop:Heap', '0:00:00.214000')
('pop:TeQ', '0:00:00.299000')

Es sieht aus wie das. Es ist weniger anders als Push, aber es ist immer noch der gleiche Trend. Eigentlich wollte ich mit M spielen, indem ich den Grad der Duplizierung änderte, aber mir wurde klar, dass es für Queue und Heapq nicht viel Sinn macht, und so beschloss ich, einen Vergleich im Hand-Cue anzustellen. Beim Vergleich mit anderen als Hand Cue http://stackoverflow.com/questions/9969236/how-to-implement-priority-queues-in-python Es schien gut, es mit etwas zu vergleichen, aber ich machte es minderwertig.

Vergleich von M-Koeffizient und Geschwindigkeit bei Änderung des Überlappungsgrades

Experiment A.

Initialisieren

initializeA.py


#Erzeugen Sie eine zufällige Folge von N.
import random
N = 1000000
M = 40000
target = range(0,N)
for n in range(N-1,-1,-1):
  target[n] = random.randint(0,M-1)

Implementierungsergebnisse

testA.py


d = datetime.datetime(1,1,1)
for m in [2,5,10,20]:
    time1 = d.now()
    v = []
    dd = {}
    for n in range(0,N):
        v = tepush(v, dd, m*M, n, target[n])
    time2 = d.now()
    for n in range(0,M):
        tepop(v, dd)
    time3 = d.now()
    print('push:TeQ_' + str(m),(time2 - time1).__str__())
    print('pop:TeQ_' + str(m),(time3 - time2).__str__())

Ergebnis A.


('push:TeQ_2', '0:00:02.731000')
('pop:TeQ_2', '0:00:00.193000')
('push:TeQ_5', '0:00:01.794000')
('pop:TeQ_5', '0:00:00.527000')
('push:TeQ_10', '0:00:01.667000')
('pop:TeQ_10', '0:00:00.711000')
('push:TeQ_20', '0:00:01.605000')
('pop:TeQ_20', '0:00:00.581000')

Der Grund, warum 20 Pops schneller sind, ist, dass sich das zweite Mal 20 * 40000 und 10 * 40000 überlappen, was bedeutet, dass sie sich immerhin im selben Zustand befinden. .. .. HM.

Versuch B.

Initialisieren

initializeB.py


#Erzeugen Sie eine zufällige Folge von N.
import random
N = 1000000
M = 4000
target = range(0,N)
for n in range(N-1,-1,-1):
  target[n] = random.randint(0,M-1)

Implementierungsergebnisse

testB.py


d = datetime.datetime(1,1,1)
for m in [2,5,10,20]:
    time1 = d.now()
    v = []
    dd = {}
    for n in range(0,N):
        v = tepush(v, dd, m*M, n, target[n])
    time2 = d.now()
    for n in range(0,M):
        tepop(v, dd)
    time3 = d.now()
    print('push:TeQ_' + str(m),(time2 - time1).__str__())
    print('pop:TeQ_' + str(m),(time3 - time2).__str__())

Ergebnis B.


('push:TeQ_2', '0:00:02.927000')
('pop:TeQ_2', '0:00:00.013000')
('push:TeQ_5', '0:00:02.035000')
('pop:TeQ_5', '0:00:00.018000')
('push:TeQ_10', '0:00:01.929000')
('pop:TeQ_10', '0:00:00.093000')
('push:TeQ_20', '0:00:01.846000')
('pop:TeQ_20', '0:00:00.026000')

Auch nach mehrmaligem Versuch ändert sich an dieser Tendenz nicht viel. Warum. Selbst wenn die Reihenfolge geändert wird, bleiben 20 überwiegend schneller als 10. HM. .. ..

Zusammenfassung

Ich habe das Gefühl, dass ich nicht das Äquivalent einer Speicherbereinigung oder Neuindizierung tun muss.

Recommended Posts

Ich möchte eine Prioritätswarteschlange erstellen, die mit Python (2.7) aktualisiert werden kann.
Ich möchte mit Python ein Fenster erstellen
Ich habe versucht, eine Klasse zu erstellen, mit der Json in Python problemlos serialisiert werden kann
Ich möchte eine Variable in einen Python-String einbetten
Ich möchte Timeout einfach in Python implementieren
Ich möchte in Python schreiben! (2) Schreiben wir einen Test
Ich möchte eine Datei mit Python zufällig testen
Ich möchte mit einem Roboter in Python arbeiten.
Ich möchte Python mit VS-Code ausführen können
Ich möchte eine schöne Ergänzung zu input () in Python hinzufügen
Ein Mechanismus zum Aufrufen von Ruby-Methoden aus Python, der in 200 Zeilen ausgeführt werden kann
[Python3] Code, der verwendet werden kann, wenn Sie ein Bild in einer bestimmten Größe ausschneiden möchten
Ich wollte ein Programm mit umgekehrter polnischer Notation in Python erstellen (Bestimmung, ob eine Zeichenfolge in einen numerischen Wert konvertiert werden kann)
Ich möchte einen Platzhalter verwenden, den ich mit Python entfernen möchte
Ich möchte in der Einschlussnotation drucken
So richten Sie einen einfachen SMTP-Server ein, der lokal in Python getestet werden kann
Qiskit: Ich möchte eine Schaltung erstellen, die beliebige Zustände erzeugt! !!
Ich möchte eine Python-Umgebung erstellen
Ich habe ein Shuffle gemacht, das mit Python zurückgesetzt (zurückgesetzt) werden kann
[Python3] Code, der verwendet werden kann, wenn Sie die Größe von Bildern Ordner für Ordner ändern möchten
Ich möchte eine Pipfile erstellen und im Docker wiedergeben
Ich habe eine Webanwendung in Python erstellt, die Markdown in HTML konvertiert
Ich möchte eine in Python in PDF konvertierte Tabelle wieder in CSV konvertieren
Ich habe versucht, einen Formatierer zu entwickeln, der Python-Protokolle in JSON ausgibt
Ich möchte einen Teil der Excel-Zeichenfolge mit Python einfärben
Ich möchte Affenpatches nur teilweise sicher mit Python machen
Ich möchte Dunnetts Test in Python machen
Ich möchte einfach ein Rauschmodell erstellen
Ein Memo, das ich schnell in Python geschrieben habe
So erstellen Sie eine JSON-Datei in Python
Ich möchte ein Spiel mit Python machen
Ich möchte verschachtelte Dicts in Python zusammenführen
Ich möchte eine Art von Implementierung erstellen, die angeschlossen werden kann
Ich möchte mit Python in eine Datei schreiben
Ich möchte den Fortschritt in Python anzeigen!
Ich habe einen Tri-Tree geschrieben, der für die Implementierung von Hochgeschwindigkeitswörterbüchern in D-Sprache und Python verwendet werden kann
Erstellen Sie ein Plugin, mit dem Sie in Python nach Registerkarten für Sublime Text 3 suchen können
Ich habe PyQCheck, eine Bibliothek, die QuickCheck mit Python ausführen kann, in PyPI registriert.
So installieren Sie die Python-Bibliothek, die von Pharmaunternehmen verwendet werden kann
Ich möchte ein Programm ausführen und verteilen, das die Größe von Bildern in Python3 + Pyinstaller ändert
Ich möchte eine WEB-Anwendung mit den Daten von League of Legends ① erstellen
Python-Programm ist langsam! Ich möchte beschleunigen! In einem solchen Fall ...
Ich habe versucht, ein scheinbar Windows-Snipper-Tool mit Python zu implementieren
Ich möchte in Python schreiben! (1) Überprüfung des Codeformats
Ich möchte schnell UUID generieren (Gedenknotiz) ~ Python Edition ~
Ich möchte mit einem Knopf am Kolben übergehen
Auch mit JavaScript möchte ich Python `range ()` sehen!
Erstellen Sie ein Plug-In, das Python Doctest auf Vim ausführt (2)
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
Erstellen Sie ein Plug-In, um Python Doctest mit Vim (1) auszuführen.
Erstellen Sie in Python einen Dekorator, der Argumente dynamisch akzeptiert. Erstellen Sie einen Dekorator
[Python] Ich möchte aus einer verschachtelten Liste einen Taple machen
Ich möchte in Python schreiben! (3) Verwenden Sie Mock
Ich möchte manuell eine Legende mit matplotlib erstellen
Ich möchte R-Datensatz mit Python verwenden
Ich möchte einen Quantencomputer mit Python betreiben
Ich möchte am Ende etwas mit Python machen
Ich möchte Strings in Kotlin wie Python manipulieren!