2009-05-10 16 views
1

Quelqu'un peut-il m'aider à accélérer l'implémentation j2ME de l'algorithme de Dijkstra? J'ai deux boucles, l'une dans l'autre. Comme cetteL'algorithme de Dijkstra le plus rapide pour j2ME

while(for each item in Q) 
{ 
    //...do something. 

    //the following loop is to find the minimum 
    for(all un-visited nodes in Q) 
    { 
     //.. do something to get min. 
    } 
} 

J'ai presque 23000 noeuds et arêtes les reliant 50000 ... La boucle interne exécute en moyenne 169330131 fois après toutes les améliorations mentionnées ci-dessous. Cela prend 5 minutes pour compléter sur mon mobile w910i et plus de minutes sur mon émulateur. Cela semble trop pour moi. Des suggestions d'amélioration? J'ai les améliorations suivantes déjà implémentées.

  1. Utilisation d'un tableau à la place du vecteur.
  2. Assurez-vous que la boucle interne ne prend pas en compte les nœuds visités. Tous mes nœuds visités sont à la fin du tableau et le nœud I connaît le nombre. Donc, je peux facilement les ignorer complètement.

Répondre

1

Quelque chose ne va pas avec votre implémentation. Sa complexité est O (E + V * log2 (V)).

Cela signifie 50000 + 23000 * ~ 15 = 400 000 itérations.

Votre complexité actuelle est presque O (V^2).

2

Je pense que votre algorithme dans la question est faux. La boucle intérieure devrait se pencher sur chaque voisin unvisited de l'élément dans la boucle extérieure:

for each (item in Q) 
{ 
    for each (unvisited neighbour of item) 
    { 
    } 
} 

Comparez avec le pseudocode implementation in wikipedia:

1 function Dijkstra(Graph, source): 
2  for each vertex v in Graph:   // Initializations 
3   dist[v] := infinity    // Unknown distance function from source to v 
4   previous[v] := undefined   // Previous node in optimal path from source 
5  dist[source] := 0      // Distance from source to source 
6  Q := the set of all nodes in Graph 
     // All nodes in the graph are unoptimized - thus are in Q 
7  while Q is not empty:     // The main loop 
8   u := vertex in Q with smallest dist[] 
9   if dist[u] = infinity: 
10    break       // all remaining vertices are inaccessible 
11   remove u from Q 
12   for each neighbor v of u:   // where v has not yet been removed from Q. 
13    alt := dist[u] + dist_between(u, v) 
14    if alt < dist[v]:    // Relax (u,v,a) 
15     dist[v] := alt 
16     previous[v] := u 
17  return previous[] 
+0

J'ai référé cet algorithme. J'ai trouvé un algorithme plus simple à un autre endroit. S'il vous plaît noter que si je devais implémenter celui dans Wikipedia, il y a deux boucles internes. alors que Q n'est pas vide: // Boucle extérieure. u: = sommet dans Q avec le plus petit dist []; // première boucle interne. .... pour chaque voisin v de: // Deuxième boucle interne. La deuxième boucle interne est plus petite. Il peut exécuter un maximum de 4-5 car il y a au plus 5 arêtes pour chaque nœud. Le nombre de nœuds ayant plus de 2 arêtes est de 1000 sur 23 000 nœuds au total. Ainsi, le temps d'exécution de la boucle interne est négligeable. – dmantamp

+0

Avez-vous lu la section dans le wikipedia sur le temps de fonctionnement? Il suggère d'utiliser des listes d'adjacence et un tas binaire ou une autre structure comme une file d'attente prioritaire - ceci supprimera largement cette première boucle interne –

+0

Regardez de plus près, Deekshit - si vous utilisez une file d'attente prioritaire (un tas) pour Q, trouver le Le plus petit élément de Q est O (1), ce qui fait que le temps d'exécution total O (n + m) est égal au nombre de nœuds et d'arêtes. –

1

j'ai parlé cet algorithme. J'ai trouvé un algorithme plus simple à un autre endroit. S'il vous plaît noter que si je devais implémenter celui dans Wikipedia, il y a deux boucles internes.

while Q is not empty: //Outer loop. 
    u := vertex in Q with smallest dist[];// First inner loop. 
    .... 
    for each neighbor v of u: //Second inner loop. 

La deuxième boucle interne est plus petite. Il peut exécuter un maximum de 4-5 car il y a au plus 5 arêtes pour chaque nœud. Le nombre de nœuds ayant plus de 2 arêtes est de 1000 sur 23 000 nœuds au total. Ainsi, le temps d'exécution de la boucle interne est négligeable. La première boucle interne est le problème. Trouver le plus petit noeud. Comme je dois l'exécuter sur un appareil j2ME, je dois le faire pour prendre le moins d'espace possible.

+0

Est-ce négligeable? L'avez-vous profilé et testé?Le pseudo-code ci-dessus * est l'algorithme de Dijkstra, donc non; la boucle interne est requise. Comme l'a dit Roman, votre algorithme est presque presque O (V^2), mais si vous implémentez l'algorithme correctement, sans hypothèses ni optimisations prématurées, vous obtiendrez la bonne complexité O(). – GManNickG

+0

Oui, je l'ai fait. Le nombre maximum de fois que la première boucle interne exeution pour chaque itération de l'exécution de la boucle externe est 23000 (nombre de notes). Mais la seconde boucle interne est exécutée seulement 5 fois (le nombre maximum d'arêtes pour chaque nœud). Considérons mon exemple où j'ai 25000 nœuds. Et je trouve le chemin le plus court en 1000ème itération. Ainsi, la seconde boucle interne exécute un minimum de 24000 pour chaque itération de la boucle externe. C'est 1000 * 25000. Mais la deuxième boucle interne ne prend que 5 itérations. C'est 1000 * 5 (max). Donc, seul le goulot d'étranglement est la première boucle interne. – dmantamp

+0

Lorsque j'ai testé la deuxième boucle ne consomme guère 2-3 secondes de temps d'exécution. Mais la première boucle est vraiment lourde. J'ai essayé de réduire le temps de moitié en économisant la deuxième distance minimale. Cela a réduit de 30% le temps d'exécution. Mais a augmenté la complexité du code. BTW, le programme ne prend pas plus de 2 secondes sur mon PC de bureau. Cela prend presque 5 minutes sur mon mobile ou mon émulateur. – dmantamp