[GO] Je souhaite créer une file d'attente prioritaire pouvant être mise à jour avec Python (2.7)

Aperçu

Créez et jouez avec des files d'attente prioritaires qui peuvent mettre à jour des éléments. Pour être précis, pousser le même élément avec des priorités différentes crée une file d'attente prioritaire qui remplace les priorités.

Synopsis

En raison de la référence rapide de l'algorithme, j'avais besoin d'utiliser une file d'attente prioritaire, mais j'ai recherché "file d'attente prioritaire Python" et elle apparaît en haut. http://docs.python.jp/2/library/heapq.html Quand je l'ai regardé, il a dit quelque chose de terrible.

Les files d'attente prioritaires sont une utilisation courante des tas et présentent quelques difficultés de mise en œuvre:

  • Stabilité du tri: Comment deux tâches d'égale priorité peuvent-elles être renvoyées dans l'ordre où elles ont été initialement ajoutées? --Dans le futur Python 3, les comparaisons taple seront divisées en paires (priorité, tâche) si les priorités sont égales et que la tâche n'a pas d'ordre de comparaison par défaut.

La solution aux deux premières difficultés consiste à enregistrer l'élément sous la forme d'une liste à trois éléments contenant la priorité, le numéro de l'élément et la tâche. Ce numéro d'article agit comme un bris d'égalité pour garantir que deux tâches de même priorité sont renvoyées dans l'ordre dans lequel elles ont été ajoutées. Et comme les deux numéros d'éléments ne sont jamais égaux, la comparaison de tapple ne peut pas essayer de comparer les deux tâches directement. La difficulté restante est principalement de trouver des tâches ouvertes, de modifier leurs priorités ou de les supprimer complètement. La recherche d'une tâche est effectuée par un dictionnaire qui pointe vers des éléments de la file d'attente. La suppression d'éléments ou la modification de leurs priorités est plus difficile car elle rompt les relations immuables de la structure du tas. Une solution possible est donc de marquer l'élément comme non valide et d'ajouter l'élément de priorité modifié si nécessaire:

Eh bien, je sais ce que vous dites. Je me suis demandé si Python ne fournissait pas de files d'attente prioritaires par défaut, car heapq dit quelque chose comme ça. Cependant, ce n'est pas le cas et il existe une file d'attente appropriée .PriorityQueue (). Cependant, bien qu'il y en ait, il semble que cela ne signifie pas que le processus de mise à jour peut être effectué immédiatement en utilisant ce PriorityQueue (). De plus, compte tenu de ce qui est écrit sur cette page, j'étais curieux de savoir à quel point la vitesse de calcul serait meilleure ou pire ~~ Je m'en fiche ~~.

conception

Une file d'attente avec des priorités faites à la main (ci-après dénommée «file d'attente manuelle») se compose d'une liste de tapples appelée (sortkey, (valeur, génération)) et d'un dictionnaire qui contient une génération pour chaque valeur. La suppression est une image qui n'est pas réellement effectuée comme décrit ci-dessus, mais est effectuée par marquage, mais elle est contrôlée en enregistrant le numéro de dernière génération dans le dictionnaire et en n'utilisant pas les dernières données. Je vais. De plus, étant donné que les performances de recherche se détériorent lorsque les éléments sont accumulés, la suppression des données + la reconstruction du tas doivent être effectuées de manière garbage collection. En ce qui concerne le timing du "garbage collection" ici, j'ai décidé de le garder comme une constante m appropriée, et de le reconstruire lorsque le nombre d'éléments (le nombre des parenthèses les plus à l'extérieur du taple compté comme 1) dépasse m. Etc.

Dans ce design "hand cue",

--push → heapq.heappush () pour mettre à jour le dictionnaire, et si la taille dépasse m, re-tas uniquement avec la dernière génération

Je vais le faire comme ça. L'accessibilité aléatoire aux éléments de la file d'attente est quelque chose dont nous ne nous soucions pas pour l'instant. Si vous donnez une valeur au dictionnaire, il utilisera plus de mémoire, mais en théorie, vous pouvez y accéder de manière aléatoire.

la mise en oeuvre

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: #Reconstruire le tas
        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) 

Cela permet de "remplacer" la valeur correspondant à la même valeur de la même manière que celle décrite dans la conception.

Comparaison avec d'autres files d'attente

Comparez avec Queue.PriorityQueue ().

Initialisation

Pour le moment, effectuez l'initialisation suivante.

initialize.py


#Générer une séquence aléatoire de 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__())

résultat push


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

Ça ressemble à ça. TeQ> Heap car il existe de nombreuses comparaisons, mais c'est beaucoup plus rapide que 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__())

résultat pop


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

Ça ressemble à ça. C'est moins différent que push, mais c'est toujours la même tendance. En fait, je voulais jouer avec M en changeant le degré de duplication, mais j'ai réalisé que cela n'avait pas beaucoup de sens pour Queue et heapq, alors j'ai décidé de faire une comparaison dans la queue de la main. Lors de la comparaison avec un signal autre que manuel http://stackoverflow.com/questions/9969236/how-to-implement-priority-queues-in-python Cela semblait bon de le comparer à quelque chose, mais je l'ai rendu inférieur.

Comparaison du coefficient M et de la vitesse lorsque le degré de chevauchement est modifié

Expérience A

Initialisation

initializeA.py


#Générer une séquence aléatoire de 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)

Résultats de la mise en œuvre

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__())

Résultat 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')

La raison pour laquelle 20 pops plus rapides est que 20 * 40000 et 10 * 40000 se chevauchent, de sorte qu'il se retrouve dans le même état. .. .. HM.

Expérience B

Initialisation

initializeB.py


#Générer une séquence aléatoire de 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)

Résultats de la mise en œuvre

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__())

Résultat 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')

Même après avoir essayé plusieurs fois, cette tendance ne change pas grand-chose. Pourquoi. Même si l'ordre est modifié, 20 reste extrêmement plus rapide que 10. HM. .. ..

Résumé

J'ai l'impression que je n'ai pas à faire l'équivalent de la réindexation ou du ramassage des ordures.

Recommended Posts

Je souhaite créer une file d'attente prioritaire pouvant être mise à jour avec Python (2.7)
Je veux créer une fenêtre avec Python
J'ai essayé de créer une classe qui peut facilement sérialiser Json en Python
Je souhaite intégrer une variable dans une chaîne Python
Je veux facilement implémenter le délai d'expiration en python
Je veux écrire en Python! (2) Écrivons un test
Je veux échantillonner au hasard un fichier avec Python
Je veux travailler avec un robot en python.
Je veux pouvoir exécuter Python avec VS Code
Je veux ajouter un joli complément à input () en python
Un mécanisme pour appeler des méthodes Ruby à partir de Python qui peut être fait en 200 lignes
[Python3] Code qui peut être utilisé lorsque vous souhaitez découper une image dans une taille spécifique
Je voulais faire un programme de notation polonaise inversée en Python (détermination de savoir si une chaîne de caractères peut être convertie en valeur numérique)
Je souhaite utiliser un caractère générique que je souhaite décortiquer avec Python remove
Je veux imprimer dans la notation d'inclusion
Comment configurer un serveur SMTP simple qui peut être testé localement en Python
Qiskit: Je veux créer un circuit qui crée des états arbitraires! !!
Je veux créer un environnement Python
J'ai fait un shuffle qui peut être réinitialisé (inversé) avec Python
[Python3] Code qui peut être utilisé lorsque vous souhaitez redimensionner des images dossier par dossier
Je veux créer un fichier pip et le refléter dans le menu fixe
J'ai créé une application Web en Python qui convertit Markdown en HTML
Je souhaite convertir une table convertie en PDF en Python en CSV
J'ai essayé de développer un formateur qui génère des journaux Python en JSON
Je veux colorer une partie de la chaîne Excel avec Python
Je veux faire un patch monkey seulement en partie en toute sécurité avec Python
Je veux faire le test de Dunnett en Python
Je souhaite créer facilement un modèle de bruit
Un mémo que j'ai écrit un tri rapide en Python
Comment créer un fichier JSON en Python
Je veux faire un jeu avec Python
Je veux fusionner des dictionnaires imbriqués en Python
Je souhaite créer un type d'implémentation pouvant être branché
Je veux écrire dans un fichier avec Python
Je veux afficher la progression en Python!
J'ai écrit un tri-arbre qui peut être utilisé pour l'implémentation de dictionnaire à grande vitesse en langage D et Python
Créez un plugin qui vous permet de rechercher les onglets Sublime Text 3 en Python
J'ai enregistré PyQCheck, une bibliothèque qui peut effectuer QuickCheck avec Python, dans PyPI.
Comment installer la bibliothèque Python qui peut être utilisée par les sociétés pharmaceutiques
Je veux exécuter et distribuer un programme qui redimensionne les images Python3 + pyinstaller
Je souhaite créer une application WEB en utilisant les données de League of Legends ①
Le programme Python est lent! Je veux accélérer! Dans ce cas ...
J'ai essayé d'implémenter ce qui semble être un outil de snipper Windows avec Python
Je veux écrire en Python! (1) Vérification du format de code
Je veux générer rapidement UUID (memo memo) ~ Edition Python ~
Je veux faire la transition avec un bouton sur le ballon
Même avec JavaScript, je veux voir Python `range ()`!
Créer un plugin pour exécuter Python Doctest sur Vim (2)
J'ai essayé d'implémenter un pseudo pachislot en Python
Créez un plug-in pour exécuter Python Doctest avec Vim (1)
En Python, créez un décorateur qui accepte dynamiquement les arguments Créer un décorateur
[Python] Je veux faire d'une liste imbriquée un taple
Je veux écrire en Python! (3) Utiliser des simulacres
Je souhaite créer manuellement une légende avec matplotlib
Je veux utiliser le jeu de données R avec python
Je veux faire fonctionner un ordinateur quantique avec Python
Je veux faire quelque chose avec Python à la fin
Je veux manipuler des chaînes dans Kotlin comme Python!