autre: Ajout de commentaires dans l'ensemble de nos codes produits
This commit is contained in:
parent
cfb1accd01
commit
0052d67e9f
10 changed files with 90 additions and 40 deletions
|
|
@ -110,6 +110,7 @@ public class ArcInspectorFactory {
|
|||
}
|
||||
};
|
||||
|
||||
// Ajout de l'ArcInspector qui évalue les PCC en temps à vélo
|
||||
public static class BicyleByTime implements ArcInspector {
|
||||
static int maxBicycleSpeed = 20;
|
||||
|
||||
|
|
@ -142,6 +143,7 @@ public class ArcInspectorFactory {
|
|||
}
|
||||
}
|
||||
|
||||
// Ajout de l'ArcInspector qui évalue les PCC en distance à vélo
|
||||
public static class BicyleByLength implements ArcInspector {
|
||||
static int maxBicycleSpeed = 20;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,16 +4,25 @@ import org.insa.graphs.model.Node;
|
|||
|
||||
public class AStarAlgorithm extends DijkstraAlgorithm {
|
||||
|
||||
/*
|
||||
L'algorithme A* est une variante de Dijkstra.
|
||||
Au lieu de réimplémenter bêtement un algorithme tout entier, nous nous sommes rendu compte que l'on pouvait simplement modifier une fonction createLabel()
|
||||
et que l'ensemble des itérations restaient les mêmes. Notre classe AStarAlgorithm hérite donc de DijkstraAlgorithm, et on modifie seulement la fonction createLabel().
|
||||
*/
|
||||
|
||||
public AStarAlgorithm(ShortestPathData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Label createLabel(Node node) {
|
||||
final LabelStar labelStar = new LabelStar(node);
|
||||
final ShortestPathData data = (ShortestPathData)this.data;
|
||||
// Création du LabelStar "vide"
|
||||
final LabelStar labelStar = new LabelStar(node);
|
||||
|
||||
// Contrairement à Dijkstra où on créé juste un Label "vide", ici on doit en plus calculer la distance entre le Node et le départ du chemin.
|
||||
final Double distance = data.getDestination().getPoint().distanceTo(node.getPoint()); // en mètres
|
||||
|
||||
// En fonction de si on fait un PCC en distance ou en temps de trajet, notre heuristique ne sera pas la même
|
||||
switch (data.getMode()) {
|
||||
case LENGTH:
|
||||
labelStar.setCoutEstime(distance); // en mètres
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ public class DijkstraAlgorithm extends ShortestPathAlgorithm {
|
|||
protected HashMap<Integer, Label> labels; // clé-valeur pour retrouver le label associé à un noeud à partir de son id
|
||||
protected BinaryHeap<Label> heap; // tas binaire pour retrouver le min en temps constant
|
||||
|
||||
|
||||
// Fonction pour créer un label inexistant, à override pour utiliser les LabelStar
|
||||
// Fonction pour créer un label inexistant. Cette fonction sera à remplacer lors de l'implémentation de A*
|
||||
protected Label createLabel(Node node) {
|
||||
return new Label(node);
|
||||
}
|
||||
|
|
@ -32,18 +31,24 @@ public class DijkstraAlgorithm extends ShortestPathAlgorithm {
|
|||
protected ShortestPathSolution doRun() {
|
||||
final ShortestPathData data = getInputData();
|
||||
|
||||
// Initialisation du tas binaire et de la HashMap contenant les Labels
|
||||
this.labels = new HashMap<>();
|
||||
this.heap = new BinaryHeap<>();
|
||||
|
||||
// Création d'un Label pour le Node de départ, et ajout dans les structures précédentes
|
||||
Label currentLabel = this.createLabel(data.getOrigin());
|
||||
currentLabel.setCoutRealise(0D);
|
||||
this.heap.insert(currentLabel);
|
||||
this.labels.put(data.getOrigin().getId(), currentLabel);
|
||||
|
||||
// Boucle principale de l'algorithme, que l'on exécutera tant que la destination n'est pas atteinte,
|
||||
// ou si l'on vient à marquer un noeud de coût infini (cela veut dire que l'on change de composante connexe).
|
||||
boolean destinationReached = false;
|
||||
notifyOriginProcessed(data.getOrigin());
|
||||
while (!destinationReached && !this.heap.isEmpty()) {
|
||||
// On récupère le Label (et donc le Node associé) de coût minimal (et non marqué, car les Labels marqués sont retirés du tas binaire)
|
||||
currentLabel = this.heap.deleteMin();
|
||||
// Si coût infini, on arrête la boucle car on a exploré toute la composante connexe du noeud de départ.
|
||||
if (currentLabel.getTotalCost() == Double.MAX_VALUE)
|
||||
break;
|
||||
|
||||
|
|
@ -52,31 +57,37 @@ public class DijkstraAlgorithm extends ShortestPathAlgorithm {
|
|||
|
||||
currentLabel.setMarque(true);
|
||||
notifyNodeMarked(currentNode);
|
||||
// On constate que les coûts des sommets marqués est bel et bien croissant
|
||||
|
||||
// On constate bien que les coûts des sommets marqués sont bel et bien croissants
|
||||
// System.out.println("-> Sommet marqué: " + currentLabel.getCoutRealise());
|
||||
|
||||
// Si on atteint notre destination, on arrête l'algo
|
||||
// Si l'on atteint notre destination, on arrête l'algorithme
|
||||
if (currentNode.equals(data.getDestination())) {
|
||||
destinationReached = true;
|
||||
} else {
|
||||
// On parcours l'ensemble des successeurs du Node courrant (à travers ses Arcs)
|
||||
for (final Arc arc : currentNode.getSuccessors()) {
|
||||
// C'est cette condition qui permet de filtrer les arcs non autorisés (exemple: l'autoroute alors que l'on est un piéton)
|
||||
if (data.isAllowed(arc)) {
|
||||
final Node successorNode = arc.getDestination();
|
||||
//System.out.println("successorNode = " + successorNode);
|
||||
// On récupère le Label associé au Node successorNode, et à défaut, on en créé un nouveau (de coût infini donc)
|
||||
final Label successorLabel = Optional.ofNullable(this.labels.get(successorNode.getId())).orElse(this.createLabel(successorNode));
|
||||
//System.out.println("successorLabel = " + successorLabel);
|
||||
|
||||
|
||||
// Si on peut réduire le cout du successorLabel en passant par le Node courrant, on met à jour l'étiquette.
|
||||
if (successorLabel.getTotalCost() > currentLabel.getTotalCost() + data.getCost(arc)) {
|
||||
// On supprime du tas binaire l'ancienne étiquette
|
||||
try {
|
||||
this.heap.remove(successorLabel);
|
||||
} catch(ElementNotFoundException e) {
|
||||
// BinaryHeap#remove a échoué, donc ça veut dire qu'on doit juste insérer, pas mettre à jour, mais ça ne change rien au niveau du code
|
||||
// BinaryHeap remove a échoué, donc ça veut dire qu'on doit juste insérer, pas mettre à jour, mais ça ne change rien au niveau du code
|
||||
}
|
||||
|
||||
notifyNodeReached(successorNode);
|
||||
|
||||
// On met à jour le coût et l'arc parent sur l'étiquette
|
||||
successorLabel.setCoutRealise(currentLabel.getCoutRealise() + data.getCost(arc));
|
||||
successorLabel.setArc(arc);
|
||||
// On insère la nouvelle étiquette dans les structures (tas binaire et HashMap)
|
||||
this.heap.insert(successorLabel);
|
||||
this.labels.put(successorNode.getId(), successorLabel);
|
||||
}
|
||||
|
|
@ -85,14 +96,17 @@ public class DijkstraAlgorithm extends ShortestPathAlgorithm {
|
|||
}
|
||||
}
|
||||
|
||||
// Arrivé ici, l'algorithme est soit arrivé à destination (dans ce cas destinationReached = true), soit il est sorti de sa composante connexe.
|
||||
ShortestPathSolution solution = null;
|
||||
// Si on a trouvé un PCC
|
||||
if (destinationReached) {
|
||||
notifyDestinationReached(data.getDestination());
|
||||
|
||||
// On part de la fin, et on remonte petit à petit vers le sommet d'origine
|
||||
// On part de la fin, et on remonte petit à petit vers le sommet d'origine, pour construire le Path à partir des arcs
|
||||
final List<Arc> arcs = new ArrayList<>();
|
||||
Node currentNode = data.getDestination();
|
||||
while (currentNode != data.getOrigin()) {
|
||||
// On récupère l'arc associé au Node courrant
|
||||
final Arc arc = labels.get(currentNode.getId()).getArc();
|
||||
if (arc != null) {
|
||||
arcs.add(arc);
|
||||
|
|
@ -102,9 +116,16 @@ public class DijkstraAlgorithm extends ShortestPathAlgorithm {
|
|||
}
|
||||
}
|
||||
|
||||
final Path path = new Path(data.getGraph(), arcs.reversed());
|
||||
solution = new ShortestPathSolution(data, Status.OPTIMAL, path);
|
||||
if (currentNode == data.getOrigin()) {
|
||||
// On construit la solution, en pensant bien à inverser la liste des arcs car on veut un chemin du départ vers l'arrivée et pas l'inverse
|
||||
final Path path = new Path(data.getGraph(), arcs.reversed());
|
||||
solution = new ShortestPathSolution(data, Status.OPTIMAL, path);
|
||||
} else {
|
||||
// On construit un objet Solution infaisable si on a pas réussi à reconstruire le chemin
|
||||
solution = new ShortestPathSolution(data, Status.INFEASIBLE);
|
||||
}
|
||||
} else {
|
||||
// On construit un objet Solution infaisable si on a pas atteint la destination
|
||||
solution = new ShortestPathSolution(data, Status.INFEASIBLE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,15 +37,9 @@ public class Label implements Comparable<Label> {
|
|||
return this.getCoutRealise();
|
||||
}
|
||||
|
||||
// Cette fonction sert à trier les Labels entre eux (et aussi, parceque LabelStar hérite de Label, les LabelStars entre eux)
|
||||
@Override
|
||||
public int compareTo(Label l) {
|
||||
/*if (this instanceof LabelStar && l instanceof LabelStar) {
|
||||
System.out.println("==> Comparaison LabelStar vs LabelStar");
|
||||
} else {
|
||||
System.out.println("==> Comparaison Label vs Label");
|
||||
}
|
||||
System.out.println(this);
|
||||
System.out.println(l);*/
|
||||
// si deux nodes ont le même coût, on compare leur estimation (si LabelStar)
|
||||
int cmp1 = this.getTotalCost().compareTo(l.getTotalCost());
|
||||
if (cmp1 == 0) {
|
||||
|
|
@ -55,7 +49,7 @@ public class Label implements Comparable<Label> {
|
|||
if (cmp2 != 0) return cmp2;
|
||||
}
|
||||
|
||||
// Soit ce n'est pas des LabelStar, soit ils ont meme cout total ET meme estimation
|
||||
// Soit ce n'est pas des LabelStar, soit ils ont le même cout total ET la même estimation
|
||||
return ((Integer) this.getNode().getId()).compareTo((Integer) l.getNode().getId());
|
||||
} else {
|
||||
return this.getTotalCost().compareTo(l.getTotalCost());
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import org.insa.graphs.model.Node;
|
|||
|
||||
public class LabelStar extends Label {
|
||||
|
||||
// On ajoute la variable coutEstime qui contiendra notre heuristique, à savoir soit le temps estimé pour revenir au départ à vol d'oiseau, soit la distance.
|
||||
private Double coutEstime;
|
||||
|
||||
public LabelStar(Node node) {
|
||||
|
|
|
|||
|
|
@ -137,14 +137,17 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
|||
public void remove(E x) throws ElementNotFoundException {
|
||||
if (this.isEmpty()) throw new ElementNotFoundException(x);
|
||||
|
||||
Stack<Integer> stack = new Stack<>();
|
||||
// Initialisation de la pile, qui nous permettra de faire un parcours en profondeur pour retrouver notre élément "x" dans le tas binaire
|
||||
final Stack<Integer> stack = new Stack<>();
|
||||
// On commence la recherche à la racine
|
||||
stack.add(0);
|
||||
while (!stack.isEmpty()) {
|
||||
int i = stack.pop();
|
||||
E current = this.array.get(i);
|
||||
// On compare l'élément au sommet de la pile avec "x"
|
||||
int comp = current.compareTo(x);
|
||||
if (comp == 0) {
|
||||
// on a trouvé notre élément
|
||||
// on a trouvé notre élément "x", on va donc le supprimer du tas binaire et faire remonter/redescendre les autres éléments afin de corriger l'arbre et qu'il reste un tas binaire
|
||||
this.currentSize--;
|
||||
if (this.currentSize > 0) {
|
||||
E lastItem = this.array.get(this.currentSize); // pas -1 car on prend l'élément qui était à la fin du tas AVANT le remove()
|
||||
|
|
@ -152,8 +155,11 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
|||
this.percolateDown(i);
|
||||
this.percolateUp(i);
|
||||
}
|
||||
// On s'assure que l'on arrête le code ici pour ne pas renvoyer l'exception finale.
|
||||
return;
|
||||
} else {
|
||||
// on a pas trouvé notre élément, on va donc continuer l'exploration des autres branches.
|
||||
|
||||
int indLeft = indexLeft(i);
|
||||
// Si l'étiquette de gauche est plus grande que x, ça ne sert à rien de continuer sur cette branche car on est sur un tas min
|
||||
if (indLeft < this.currentSize && this.array.get(indLeft).compareTo(x) <= 0) stack.push(indLeft);
|
||||
|
|
@ -164,6 +170,7 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
|||
}
|
||||
}
|
||||
|
||||
// Si on arrive ici, ça veut dire que l'on n'a pas trouvé l'élément "x" dans le tas binaire.
|
||||
throw new ElementNotFoundException(x);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package org.insa.graphs.algorithm.shortestpath;
|
|||
|
||||
public class AStarTest extends ShortestPathAlgorithmTest {
|
||||
|
||||
// Dijkstra et A* bénéficient de la même banque de test, ils héritent donc tous les deux de la classe ShortestPathAlgorithmTest
|
||||
@Override
|
||||
public ShortestPathSolution runAlgo(ShortestPathData algoData) {
|
||||
final AStarAlgorithm algo = new AStarAlgorithm(algoData);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package org.insa.graphs.algorithm.shortestpath;
|
|||
|
||||
public class DijkstraTest extends ShortestPathAlgorithmTest {
|
||||
|
||||
// Dijkstra et A* bénéficient de la même banque de test, ils héritent donc tous les deux de la classe ShortestPathAlgorithmTest
|
||||
@Override
|
||||
public ShortestPathSolution runAlgo(ShortestPathData algoData) {
|
||||
final DijkstraAlgorithm algo = new DijkstraAlgorithm(algoData);
|
||||
|
|
|
|||
|
|
@ -40,11 +40,10 @@ public abstract class ShortestPathAlgorithmTest {
|
|||
private static String MAP_HAITI = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/haiti-and-domrep.mapgr";
|
||||
private static String MAP_TOULOUSE = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/toulouse.mapgr";
|
||||
private static String MAP_FRANCE = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/france.mapgr";
|
||||
|
||||
private static Graph carreGraph, insaGraph, haitiGraph, toulouseGraph, franceGraph;
|
||||
|
||||
protected static class TestScenario {
|
||||
public final Graph graph; // chemin du fichier mapgr
|
||||
public final Graph graph;
|
||||
public final Node origin, destination;
|
||||
public final ArcInspector arcInspector;
|
||||
public final Status expectedStatus;
|
||||
|
|
@ -62,6 +61,7 @@ public abstract class ShortestPathAlgorithmTest {
|
|||
}
|
||||
};
|
||||
|
||||
// Fonction utilitaire qui prend un chemin de fichier en entrée, charge le graphe associé et le renvoi.
|
||||
private static Graph loadGraph(String pathname) {
|
||||
Graph graph = null;
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ public abstract class ShortestPathAlgorithmTest {
|
|||
objects.add(new TestScenario(insaGraph, 286, 823, Status.OPTIMAL));
|
||||
// Exemple trajet infaisable (composantes non connexes)
|
||||
objects.add(new TestScenario(haitiGraph, 265362, 92314, Status.INFEASIBLE));
|
||||
// Exemple trajet moyen, à pieds
|
||||
// Exemple trajet moyen, à pied
|
||||
objects.add(new TestScenario(toulouseGraph, 16824, 4028, Status.OPTIMAL, new ArcInspectorFactory.OnlyPedestrianByTime()));
|
||||
// Exemple trajet de longueur nulle
|
||||
objects.add(new TestScenario(insaGraph, 297, 297, Status.OPTIMAL));
|
||||
|
|
@ -129,14 +129,15 @@ public abstract class ShortestPathAlgorithmTest {
|
|||
|
||||
final ShortestPathData algoData = new ShortestPathData(scenario.graph, scenario.origin, scenario.destination, scenario.arcInspector);
|
||||
|
||||
final ShortestPathSolution solutionDijkstra = this.runAlgo(algoData);
|
||||
final ShortestPathSolution solutionAlgo = this.runAlgo(algoData);
|
||||
final ShortestPathSolution solutionBellman = new BellmanFordAlgorithm(algoData).doRun();
|
||||
|
||||
final Path pathDijkstra = solutionDijkstra.getPath();
|
||||
final Path pathAlgo = solutionAlgo.getPath();
|
||||
final Path pathBellman = solutionBellman.getPath();
|
||||
|
||||
// Comparaison des chemins issus de Bellman et de Dijkstra/A*, en comparant les coûts.
|
||||
double coutDijkstra = 0.0;
|
||||
for (final Arc arc : pathDijkstra.getArcs()) coutDijkstra += scenario.arcInspector.getCost(arc);
|
||||
for (final Arc arc : pathAlgo.getArcs()) coutDijkstra += scenario.arcInspector.getCost(arc);
|
||||
double coutBellman = 0.0;
|
||||
for (final Arc arc : pathBellman.getArcs()) coutBellman += scenario.arcInspector.getCost(arc);
|
||||
|
||||
|
|
@ -150,17 +151,20 @@ public abstract class ShortestPathAlgorithmTest {
|
|||
final ShortestPathData algoData = new ShortestPathData(scenario.graph, scenario.origin, scenario.destination, scenario.arcInspector);
|
||||
final ShortestPathSolution solution = this.runAlgo(algoData);
|
||||
|
||||
final Path dijkstraPath = solution.getPath();
|
||||
final Path algoPath = solution.getPath();
|
||||
double coutDijkstra = 0;
|
||||
for (Arc arc : dijkstraPath.getArcs()) coutDijkstra += scenario.arcInspector.getCost(arc);
|
||||
for (Arc arc : algoPath.getArcs()) coutDijkstra += scenario.arcInspector.getCost(arc);
|
||||
|
||||
// On doit comparer le cout de dijkstra (calculé au dessus) au cout du shortest path passant par les mêmes nodes.
|
||||
final List<Node> nodes = dijkstraPath.getArcs().stream().map(arc -> arc.getOrigin()).collect(Collectors.toList());
|
||||
if (!nodes.isEmpty()) nodes.add(dijkstraPath.getArcs().getLast().getDestination());
|
||||
// On doit comparer le cout du PCC issu de l'algo Dijkstra/A* (calculé au dessus) au cout du shortest path (calculé dans la classe Path) passant par les mêmes nodes.
|
||||
// D'abord on récupère tous les Nodes du PCC
|
||||
final List<Node> nodes = algoPath.getArcs().stream().map(arc -> arc.getOrigin()).collect(Collectors.toList());
|
||||
if (!nodes.isEmpty()) nodes.add(algoPath.getArcs().getLast().getDestination());
|
||||
// Puis on calcule le coût avec la méthode Path#createShortestPathFromNodes
|
||||
final Path computedPath = Path.createShortestPathFromNodes(scenario.graph, nodes);
|
||||
// On calcule le coût de notre PCC.
|
||||
double coutComputed = 0;
|
||||
for (Arc arc : computedPath.getArcs()) coutComputed += scenario.arcInspector.getCost(arc);
|
||||
|
||||
// Comparaison finale
|
||||
assertEquals(coutDijkstra, coutComputed, 0.0);
|
||||
}
|
||||
|
||||
|
|
@ -171,28 +175,34 @@ public abstract class ShortestPathAlgorithmTest {
|
|||
final ShortestPathSolution solution = this.runAlgo(algoData);
|
||||
final Path solutionPath = solution.getPath();
|
||||
|
||||
// On s'assure que le status de la solution est bien celui attendu initialement
|
||||
assertEquals(scenario.expectedStatus, solution.getStatus());
|
||||
|
||||
// Si on est sur un PCC faisable, on vérifie le respect de la règle que tout sous-chemin d'un PCC est lui même un PCC
|
||||
if (solution.isFeasible()) {
|
||||
final int solutionPathLength = solutionPath.getArcs().size();
|
||||
// Pour se faire, on prend des portions partant du départ, jusqu'à des Nodes appartenant au PCC initial
|
||||
for (int k = 1; k < (solutionPathLength/10); k++) {
|
||||
// On calcule un sous chemin, partant du même origin, mais arrivant à un point intermédiaire de la solution globale
|
||||
// On calcule un sous chemin, partant de la même origine, mais arrivant à un point intermédiaire de la solution globale
|
||||
final Node middleNode = solutionPath.getArcs().get(k*5).getOrigin();
|
||||
final ShortestPathData algoSousCheminData = new ShortestPathData(scenario.graph, scenario.origin, middleNode, scenario.arcInspector);
|
||||
final ShortestPathSolution sousCheminSolution = this.runAlgo(algoSousCheminData);
|
||||
// on s'assure qu'une solution a été trouvé pour le sous-chemin
|
||||
assertTrue(sousCheminSolution.isFeasible());
|
||||
final Path sousCheminPath = sousCheminSolution.getPath();
|
||||
// Calcul du coût du sous-chemin
|
||||
double sousCheminCost = 0.0;
|
||||
System.out.println("SousCheminPathLength: " + sousCheminPath.getArcs().size());
|
||||
for (final Arc arc : sousCheminPath.getArcs()) {
|
||||
sousCheminCost += scenario.arcInspector.getCost(arc);
|
||||
}
|
||||
|
||||
// Calcul du coût de la portion du PCC intial
|
||||
double solutionCost = 0.0;
|
||||
for (final Arc arc : solutionPath.getArcs()) {
|
||||
solutionCost += scenario.arcInspector.getCost(arc);
|
||||
if (arc.getDestination().equals(middleNode)) break; // Si on est arrivé au noeud intermédiaire, on arrête
|
||||
}
|
||||
|
||||
// Comparaison finale
|
||||
assertEquals(solutionCost, sousCheminCost, 0.0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,11 +29,13 @@ public class Path {
|
|||
public static Path createFastestPathFromNodes(Graph graph, List<Node> nodes)
|
||||
throws IllegalArgumentException {
|
||||
Path path = null;
|
||||
if (nodes.size() <= 1) {
|
||||
// Pour créer un chemin correct, il nous faut au minimum deux Nodes.
|
||||
if (nodes.size() < 2) {
|
||||
path = new Path(graph, nodes.isEmpty() ? null : nodes.get(0));
|
||||
} else {
|
||||
List<Arc> arcs = new ArrayList<Arc>();
|
||||
Node prev = null;
|
||||
// Pour chaque Node à traverser, on choisi un arc qui connecte le Node courrant au Node suivant, en sélectionnant celui de coût minimal (ici la durée de trajet)
|
||||
for (Node next : nodes) {
|
||||
if (prev != null) {
|
||||
Arc choosen = null;
|
||||
|
|
@ -67,11 +69,13 @@ public class Path {
|
|||
public static Path createShortestPathFromNodes(Graph graph, List<Node> nodes)
|
||||
throws IllegalArgumentException {
|
||||
Path path = null;
|
||||
if (nodes.size() <= 1) {
|
||||
// Pour créer un chemin correct, il nous faut au minimum deux Nodes.
|
||||
if (nodes.size() < 2) {
|
||||
path = new Path(graph, nodes.isEmpty() ? null : nodes.get(0));
|
||||
} else {
|
||||
List<Arc> arcs = new ArrayList<Arc>();
|
||||
Node prev = null;
|
||||
// Pour chaque Node à traverser, on choisi un arc qui connecte le Node courrant au Node suivant, en sélectionnant celui de coût minimal (ici la distance)
|
||||
for (Node next : nodes) {
|
||||
if (prev != null) {
|
||||
Arc choosen = null;
|
||||
|
|
|
|||
Loading…
Reference in a new issue