L'algorithme de Dijkstra m'a été enseigné comme suit
while pqueue is not empty:
distance, node = pqueue.delete_min()
if node has been visited:
continue
else:
mark node as visited
if node == target:
break
for each neighbor of node:
pqueue.insert(distance + distance_to_neighbor, neighbor)
Mais j'ai fait quelques lectures concernant l'algorithme, et beaucoup de versions que je vois utilisent la touche de diminution plutôt que l'insertion.
Pourquoi cela et quelles sont les différences entre les deux approches?
La raison d'utiliser la clé de diminution plutôt que de réinsérer des nœuds est de maintenir le nombre de nœuds dans la file d'attente prioritaire petit, ce qui maintient le nombre total de files d'attente de file d'attente prioritaire petit et le coût de chaque équilibre de file d'attente prioritaire faible.
Dans une implémentation de l'algorithme de Dijkstra qui réinsère les nœuds dans la file d'attente prioritaire avec leurs nouvelles priorités, un nœud est ajouté à la file d'attente prioritaire pour chacun des m bords du graphique. Cela signifie qu'il y a m opérations de mise en file d'attente et m opérations de retrait de file d'attente sur la file d'attente prioritaire, ce qui donne un temps d'exécution total de O (m Te + m Tré), où Te est le temps nécessaire pour mettre en file d'attente dans la file d'attente prioritaire et Tré est le temps requis pour sortir de la file d'attente prioritaire.
Dans une implémentation de l'algorithme de Dijkstra qui prend en charge la clé de diminution, la file d'attente prioritaire contenant les nœuds commence par n nœuds et à chaque étape de l'algorithme supprime un nœud. Cela signifie que le nombre total de files d'attente de tas est n. Chaque nœud aura une clé de diminution appelée potentiellement une fois pour chaque bord y menant, donc le nombre total de clés de diminution effectuées est au maximum de m. Cela donne un temps d'exécution de (n Te + n Tré + m Tk), où Tk est le temps nécessaire pour appeler la touche de diminution.
Alors, quel effet cela a-t-il sur l'exécution? Cela dépend de la file d'attente prioritaire que vous utilisez. Voici un tableau rapide qui montre les différentes files d'attente prioritaires et les temps d'exécution globaux des différentes implémentations d'algorithmes de Dijkstra:
Queue | T_e | T_d | T_k | w/o Dec-Key | w/Dec-Key
---------------+--------+--------+--------+-------------+---------------
Binary Heap |O(log N)|O(log N)|O(log N)| O(M log N) | O(M log N)
Binomial Heap |O(log N)|O(log N)|O(log N)| O(M log N) | O(M log N)
Fibonacci Heap | O(1) |O(log N)| O(1) | O(M log N) | O(M + N log N)
Comme vous pouvez le voir, avec la plupart des types de files d'attente prioritaires, il n'y a vraiment pas de différence dans le temps d'exécution asymptotique, et la version à clé de diminution ne devrait pas faire beaucoup mieux. Cependant, si vous utilisez une implémentation tas de Fibonacci de la file d'attente prioritaire, alors l'algorithme de Dijkstra sera asymptotiquement plus efficace lors de l'utilisation de la touche de diminution.
En bref, l'utilisation de la touche de diminution, plus une bonne file d'attente prioritaire, peut réduire le temps d'exécution asymptotique de Dijkstra au-delà de ce qui est possible si vous continuez à faire des files d'attente et des retraits.
Outre ce point, certains algorithmes plus avancés, tels que l'algorithme de Gabow's Shortest Paths, utilisent l'algorithme de Dijkstra comme sous-programme et s'appuient fortement sur l'implémentation de la clé de diminution. Ils utilisent le fait que si vous connaissez la plage de distances valides à l'avance, vous pouvez créer une file d'attente prioritaire super efficace en fonction de ce fait.
J'espère que cela t'aides!
En 2007, un article a étudié les différences de temps d'exécution entre l'utilisation de la version à clé de diminution et la version à insertion. Voir http://www.cs.utexas.edu/users/shaikat/papers/TR-07-54.pdf
Leur conclusion de base était de ne pas utiliser la touche de diminution pour la plupart des graphiques. Surtout pour les graphiques clairsemés, la clé non décroissante est nettement plus rapide que la version clé décroissante. Consultez le document pour plus de détails.