diff --git a/Projektgruppe_175/src/base/GraphAlgorithm.java b/Projektgruppe_175/src/base/GraphAlgorithm.java index 30ddbc7..f15d811 100644 --- a/Projektgruppe_175/src/base/GraphAlgorithm.java +++ b/Projektgruppe_175/src/base/GraphAlgorithm.java @@ -5,144 +5,203 @@ import java.util.*; /** * Abstrakte generische Klasse um Wege zwischen Knoten in einem Graph zu finden. * Eine implementierende Klasse ist beispielsweise {@link game.map.PathFinding} + * * @param Die Datenstruktur des Graphen */ public abstract class GraphAlgorithm { - /** - * Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern - * Sie weist jedem Knoten einen Wert und einen Vorgängerknoten zu. - * @param - */ - private static class AlgorithmNode { + /** + * Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern Sie weist + * jedem Knoten einen Wert und einen Vorgängerknoten zu. + * + * @param + */ + private static class AlgorithmNode { - private Node node; - private double value; - private AlgorithmNode previous; + private Node node; + private double value; + private AlgorithmNode previous; - AlgorithmNode(Node parentNode, AlgorithmNode previousNode, double value) { - this.node = parentNode; - this.previous = previousNode; - this.value = value; - } - } + AlgorithmNode(Node parentNode, AlgorithmNode previousNode, double value) { + this.node = parentNode; + this.previous = previousNode; + this.value = value; + } + } - private Graph graph; + private Graph graph; - // Diese Liste enthält alle Knoten, die noch nicht abgearbeitet wurden - private List> availableNodes; + // Diese Liste enthält alle Knoten, die noch nicht abgearbeitet wurden + private List> availableNodes; - // Diese Map enthält alle Zuordnungen - private Map, AlgorithmNode> algorithmNodes; + // Diese Map enthält alle Zuordnungen + private Map, AlgorithmNode> algorithmNodes; - /** - * Erzeugt ein neues GraphAlgorithm-Objekt mit dem dazugehörigen Graphen und dem Startknoten. - * @param graph der zu betrachtende Graph - * @param sourceNode der Startknoten - */ - public GraphAlgorithm(Graph graph, Node sourceNode) { - this.graph = graph; - this.availableNodes = new LinkedList<>(graph.getNodes()); - this.algorithmNodes = new HashMap<>(); + /** + * Erzeugt ein neues GraphAlgorithm-Objekt mit dem dazugehörigen Graphen und dem + * Startknoten. + * + * @param graph der zu betrachtende Graph + * @param sourceNode der Startknoten + */ + public GraphAlgorithm(Graph graph, Node sourceNode) { + this.graph = graph; + this.availableNodes = new LinkedList<>(graph.getNodes()); + this.algorithmNodes = new HashMap<>(); - for(Node node : graph.getNodes()) - this.algorithmNodes.put(node, new AlgorithmNode<>(node, null, -1)); + for (Node node : graph.getNodes()) + this.algorithmNodes.put(node, new AlgorithmNode<>(node, null, -1)); - this.algorithmNodes.get(sourceNode).value = 0; - } + this.algorithmNodes.get(sourceNode).value = 0; + } - /** - * Diese Methode gibt einen Knoten mit dem kleinsten Wert, der noch nicht abgearbeitet wurde, zurück und entfernt ihn aus der Liste {@link #availableNodes}. - * Sollte kein Knoten gefunden werden, wird null zurückgegeben. - * Verbindliche Anforderung: Verwenden Sie beim Durchlaufen der Liste Iteratoren - * @return Der nächste abzuarbeitende Knoten oder null - */ - private AlgorithmNode getSmallestNode() { - // TODO: GraphAlgorithm#getSmallestNode() - if(availableNodes.isEmpty()) - { - return null; - } - Iterator> iter = availableNodes.iterator(); - Iterator> iterMinElem = iter; - AlgorithmNode MinElem; - AlgorithmNode tempElem; - if(iter.hasNext()) - { - MinElem = algorithmNodes.get(iter.next()); - while (iter.hasNext()) - { - tempElem = algorithmNodes.get(iter.next()); - if(tempElem.value < MinElem.value) - { - iterMinElem = iter; - MinElem = tempElem; - } - } - iter.remove(); - return MinElem; - } - return null; - } + /** + * Diese Methode gibt einen Knoten mit dem kleinsten Wert, der noch nicht + * abgearbeitet wurde, zurück und entfernt ihn aus der Liste + * {@link #availableNodes}. Sollte kein Knoten gefunden werden, wird null + * zurückgegeben. Verbindliche Anforderung: Verwenden Sie beim Durchlaufen der + * Liste Iteratoren + * + * @return Der nächste abzuarbeitende Knoten oder null + */ + private AlgorithmNode getSmallestNode() { - /** - * Diese Methode startet den Algorithmus. Dieser funktioniert wie folgt: - * 1. Suche den Knoten mit dem geringsten Wert (siehe {@link #getSmallestNode()}) - * 2. Für jede angrenzende Kante: - * 2a. Überprüfe ob die Kante passierbar ist ({@link #isPassable(Edge)}) - * 2b. Berechne den Wert des Knotens, in dem du den aktuellen Wert des Knotens und den der Kante addierst - * 2c. Ist der alte Wert nicht gesetzt (-1) oder ist der neue Wert kleiner, setze den neuen Wert und den Vorgängerknoten - * 3. Wiederhole solange, bis alle Knoten abgearbeitet wurden + if (availableNodes.isEmpty()) { + return null; + } + Iterator> iter = availableNodes.iterator(); + Iterator> iterMinElem = iter; + AlgorithmNode MinElem; + AlgorithmNode tempElem; - * Nützliche Methoden: - * @see #getSmallestNode() - * @see #isPassable(Edge) - * @see Graph#getEdges(Node) - * @see Edge#getOtherNode(Node) - */ - public void run() { - // TODO: GraphAlgorithm#run() - } + if (iter.hasNext()) { + MinElem = algorithmNodes.get(iter.next()); + while (iter.hasNext()) { + tempElem = algorithmNodes.get(iter.next()); + if (tempElem.value < MinElem.value) { + iterMinElem = iter; + MinElem = tempElem; + } + } + iter.remove(); + return MinElem; + } - /** - * Diese Methode gibt eine Liste von Kanten zurück, die einen Pfad zu dem angegebenen Zielknoten representiert. - * Dabei werden zuerst beginnend mit dem Zielknoten alle Kanten mithilfe des Vorgängerattributs {@link AlgorithmNode#previous} zu der Liste hinzugefügt. - * Zum Schluss muss die Liste nur noch umgedreht werden. Sollte kein Pfad existieren, geben Sie null zurück. - * @param destination Der Zielknoten des Pfads - * @return eine Liste von Kanten oder null - */ - public List> getPath(Node destination) { - // TODO: GraphAlgorithm#getPath(Node) - return null; - } + return null; + } - /** - * Gibt den betrachteten Graphen zurück - * @return der zu betrachtende Graph - */ - protected Graph getGraph() { - return this.graph; - } + /** + * Diese Methode startet den Algorithmus. Dieser funktioniert wie folgt: 1. + * Suche den Knoten mit dem geringsten Wert (siehe {@link #getSmallestNode()}) + * 2. Für jede angrenzende Kante: 2a. Überprüfe ob die Kante passierbar ist + * ({@link #isPassable(Edge)}) 2b. Berechne den Wert des Knotens, in dem du den + * aktuellen Wert des Knotens und den der Kante addierst 2c. Ist der alte Wert + * nicht gesetzt (-1) oder ist der neue Wert kleiner, setze den neuen Wert und + * den Vorgängerknoten 3. Wiederhole solange, bis alle Knoten abgearbeitet + * wurden + * + * Nützliche Methoden: + * + * @see #getSmallestNode() + * @see #isPassable(Edge) + * @see Graph#getEdges(Node) + * @see Edge#getOtherNode(Node) + */ + public void run() { - /** - * Gibt den Wert einer Kante zurück. - * Diese Methode ist abstrakt und wird in den implementierenden Klassen definiert um eigene Kriterien für Werte zu ermöglichen. - * @param edge Eine Kante - * @return Ein Wert, der der Kante zugewiesen wird - */ - protected abstract double getValue(Edge edge); + AlgorithmNode v = getSmallestNode(); + + while (v != null) { + for (Edge e : graph.getEdges(v.node)) { + if (isPassable(e)) { + + AlgorithmNode n = algorithmNodes.get(e.getOtherNode(v.node)); + + double a = v.value + getValue(e); + + if (n.value == -1 || n.value > a) { + + n.value = a; + n.previous = v; + + } + + } + } + v = getSmallestNode(); + } + } - /** - * Gibt an, ob eine Kante passierbar ist. - * @param edge Eine Kante - * @return true, wenn die Kante passierbar ist. - */ - protected abstract boolean isPassable(Edge edge); + /** + * Diese Methode gibt eine Liste von Kanten zurück, die einen Pfad zu dem + * angegebenen Zielknoten representiert. Dabei werden zuerst beginnend mit dem + * Zielknoten alle Kanten mithilfe des Vorgängerattributs + * {@link AlgorithmNode#previous} zu der Liste hinzugefügt. Zum Schluss muss die + * Liste nur noch umgedreht werden. Sollte kein Pfad existieren, geben Sie null + * zurück. + * + * @param destination Der Zielknoten des Pfads + * @return eine Liste von Kanten oder null + */ + public List> getPath(Node destination) { - /** - * Gibt an, ob eine Knoten passierbar ist. - * @param node Eine Knoten - * @return true, wenn der Knoten passierbar ist. - */ - protected abstract boolean isPassable(Node node); + // Stage 1 + ArrayList> reversePath = new ArrayList>(); + + AlgorithmNode prevNode = algorithmNodes.get(destination); + if (prevNode == null) + return null; + + while (!prevNode.node.equals(destination)) { + + AlgorithmNode prevPrevNode = prevNode.previous; + + if (prevPrevNode == null) + return null; + + reversePath.add(new Edge(prevPrevNode.node, prevNode.node)); + prevNode = prevPrevNode; + + } + + // Stage 2 + Collections.reverse(reversePath); + return reversePath; + + } + + /** + * Gibt den betrachteten Graphen zurück + * + * @return der zu betrachtende Graph + */ + protected Graph getGraph() { + return this.graph; + } + + /** + * Gibt den Wert einer Kante zurück. Diese Methode ist abstrakt und wird in den + * implementierenden Klassen definiert um eigene Kriterien für Werte zu + * ermöglichen. + * + * @param edge Eine Kante + * @return Ein Wert, der der Kante zugewiesen wird + */ + protected abstract double getValue(Edge edge); + + /** + * Gibt an, ob eine Kante passierbar ist. + * + * @param edge Eine Kante + * @return true, wenn die Kante passierbar ist. + */ + protected abstract boolean isPassable(Edge edge); + + /** + * Gibt an, ob ein Knoten passierbar ist. + * + * @param node Ein Knoten + * @return true, wenn der Knoten passierbar ist. + */ + protected abstract boolean isPassable(Node node); } diff --git a/doc/Dokumentation.tex b/doc/Dokumentation.tex index 50c667c..b9e5749 100644 --- a/doc/Dokumentation.tex +++ b/doc/Dokumentation.tex @@ -90,7 +90,9 @@ \begin{itemize} \item HashSet wird verwendet, um die bisher - besuchten Knoten zu speichern. + besuchten Knoten zu speichern. Eine HashSet + hat den Vorteil, dass Elemente nur einmal + gespeichert werden können. \item ArrayDeque wird verwendet, um die nächsten Knoten, die besucht werden, zu speichern. \end{itemize}