WIP 3.1.3

This commit is contained in:
joachimschmidt557 2019-02-19 16:34:06 +01:00
parent 6102da73fa
commit f4eec30656
2 changed files with 182 additions and 121 deletions

View file

@ -5,13 +5,15 @@ import java.util.*;
/** /**
* Abstrakte generische Klasse um Wege zwischen Knoten in einem Graph zu finden. * Abstrakte generische Klasse um Wege zwischen Knoten in einem Graph zu finden.
* Eine implementierende Klasse ist beispielsweise {@link game.map.PathFinding} * Eine implementierende Klasse ist beispielsweise {@link game.map.PathFinding}
*
* @param <T> Die Datenstruktur des Graphen * @param <T> Die Datenstruktur des Graphen
*/ */
public abstract class GraphAlgorithm<T> { public abstract class GraphAlgorithm<T> {
/** /**
* Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern * Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern Sie weist
* Sie weist jedem Knoten einen Wert und einen Vorgängerknoten zu. * jedem Knoten einen Wert und einen Vorgängerknoten zu.
*
* @param <T> * @param <T>
*/ */
private static class AlgorithmNode<T> { private static class AlgorithmNode<T> {
@ -36,7 +38,9 @@ public abstract class GraphAlgorithm<T> {
private Map<Node<T>, AlgorithmNode<T>> algorithmNodes; private Map<Node<T>, AlgorithmNode<T>> algorithmNodes;
/** /**
* Erzeugt ein neues GraphAlgorithm-Objekt mit dem dazugehörigen Graphen und dem Startknoten. * Erzeugt ein neues GraphAlgorithm-Objekt mit dem dazugehörigen Graphen und dem
* Startknoten.
*
* @param graph der zu betrachtende Graph * @param graph der zu betrachtende Graph
* @param sourceNode der Startknoten * @param sourceNode der Startknoten
*/ */
@ -52,29 +56,29 @@ public abstract class GraphAlgorithm<T> {
} }
/** /**
* Diese Methode gibt einen Knoten mit dem kleinsten Wert, der noch nicht abgearbeitet wurde, zurück und entfernt ihn aus der Liste {@link #availableNodes}. * Diese Methode gibt einen Knoten mit dem kleinsten Wert, der noch nicht
* Sollte kein Knoten gefunden werden, wird null zurückgegeben. * abgearbeitet wurde, zurück und entfernt ihn aus der Liste
* Verbindliche Anforderung: Verwenden Sie beim Durchlaufen der Liste Iteratoren * {@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 * @return Der nächste abzuarbeitende Knoten oder null
*/ */
private AlgorithmNode<T> getSmallestNode() { private AlgorithmNode<T> getSmallestNode() {
// TODO: GraphAlgorithm<T>#getSmallestNode()
if(availableNodes.isEmpty()) if (availableNodes.isEmpty()) {
{
return null; return null;
} }
Iterator<Node<T>> iter = availableNodes.iterator(); Iterator<Node<T>> iter = availableNodes.iterator();
Iterator<Node<T>> iterMinElem = iter; Iterator<Node<T>> iterMinElem = iter;
AlgorithmNode<T> MinElem; AlgorithmNode<T> MinElem;
AlgorithmNode<T> tempElem; AlgorithmNode<T> tempElem;
if(iter.hasNext())
{ if (iter.hasNext()) {
MinElem = algorithmNodes.get(iter.next()); MinElem = algorithmNodes.get(iter.next());
while (iter.hasNext()) while (iter.hasNext()) {
{
tempElem = algorithmNodes.get(iter.next()); tempElem = algorithmNodes.get(iter.next());
if(tempElem.value < MinElem.value) if (tempElem.value < MinElem.value) {
{
iterMinElem = iter; iterMinElem = iter;
MinElem = tempElem; MinElem = tempElem;
} }
@ -82,42 +86,93 @@ public abstract class GraphAlgorithm<T> {
iter.remove(); iter.remove();
return MinElem; return MinElem;
} }
return null; return null;
} }
/** /**
* Diese Methode startet den Algorithmus. Dieser funktioniert wie folgt: * Diese Methode startet den Algorithmus. Dieser funktioniert wie folgt: 1.
* 1. Suche den Knoten mit dem geringsten Wert (siehe {@link #getSmallestNode()}) * Suche den Knoten mit dem geringsten Wert (siehe {@link #getSmallestNode()})
* 2. Für jede angrenzende Kante: * 2. Für jede angrenzende Kante: 2a. Überprüfe ob die Kante passierbar ist
* 2a. Überprüfe ob die Kante passierbar ist ({@link #isPassable(Edge)}) * ({@link #isPassable(Edge)}) 2b. Berechne den Wert des Knotens, in dem du den
* 2b. Berechne den Wert des Knotens, in dem du den aktuellen Wert des Knotens und den der Kante addierst * aktuellen Wert des Knotens und den der Kante addierst 2c. Ist der alte Wert
* 2c. Ist der alte Wert nicht gesetzt (-1) oder ist der neue Wert kleiner, setze den neuen Wert und den Vorgängerknoten * nicht gesetzt (-1) oder ist der neue Wert kleiner, setze den neuen Wert und
* 3. Wiederhole solange, bis alle Knoten abgearbeitet wurden * den Vorgängerknoten 3. Wiederhole solange, bis alle Knoten abgearbeitet
* wurden
*
* Nützliche Methoden: * Nützliche Methoden:
*
* @see #getSmallestNode() * @see #getSmallestNode()
* @see #isPassable(Edge) * @see #isPassable(Edge)
* @see Graph#getEdges(Node) * @see Graph#getEdges(Node)
* @see Edge#getOtherNode(Node) * @see Edge#getOtherNode(Node)
*/ */
public void run() { public void run() {
// TODO: GraphAlgorithm<T>#run()
AlgorithmNode<T> v = getSmallestNode();
while (v != null) {
for (Edge<T> e : graph.getEdges(v.node)) {
if (isPassable(e)) {
AlgorithmNode<T> 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();
}
} }
/** /**
* Diese Methode gibt eine Liste von Kanten zurück, die einen Pfad zu dem angegebenen Zielknoten representiert. * Diese Methode gibt eine Liste von Kanten zurück, die einen Pfad zu dem
* Dabei werden zuerst beginnend mit dem Zielknoten alle Kanten mithilfe des Vorgängerattributs {@link AlgorithmNode#previous} zu der Liste hinzugefügt. * angegebenen Zielknoten representiert. Dabei werden zuerst beginnend mit dem
* Zum Schluss muss die Liste nur noch umgedreht werden. Sollte kein Pfad existieren, geben Sie null zurück. * 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 * @param destination Der Zielknoten des Pfads
* @return eine Liste von Kanten oder null * @return eine Liste von Kanten oder null
*/ */
public List<Edge<T>> getPath(Node<T> destination) { public List<Edge<T>> getPath(Node<T> destination) {
// TODO: GraphAlgorithm<T>#getPath(Node<T>)
// Stage 1
ArrayList<Edge<T>> reversePath = new ArrayList<Edge<T>>();
AlgorithmNode<T> prevNode = algorithmNodes.get(destination);
if (prevNode == null)
return null; return null;
while (!prevNode.node.equals(destination)) {
AlgorithmNode<T> prevPrevNode = prevNode.previous;
if (prevPrevNode == null)
return null;
reversePath.add(new Edge<T>(prevPrevNode.node, prevNode.node));
prevNode = prevPrevNode;
}
// Stage 2
Collections.reverse(reversePath);
return reversePath;
} }
/** /**
* Gibt den betrachteten Graphen zurück * Gibt den betrachteten Graphen zurück
*
* @return der zu betrachtende Graph * @return der zu betrachtende Graph
*/ */
protected Graph<T> getGraph() { protected Graph<T> getGraph() {
@ -125,8 +180,10 @@ public abstract class GraphAlgorithm<T> {
} }
/** /**
* Gibt den Wert einer Kante zurück. * Gibt den Wert einer Kante zurück. Diese Methode ist abstrakt und wird in den
* Diese Methode ist abstrakt und wird in den implementierenden Klassen definiert um eigene Kriterien für Werte zu ermöglichen. * implementierenden Klassen definiert um eigene Kriterien für Werte zu
* ermöglichen.
*
* @param edge Eine Kante * @param edge Eine Kante
* @return Ein Wert, der der Kante zugewiesen wird * @return Ein Wert, der der Kante zugewiesen wird
*/ */
@ -134,14 +191,16 @@ public abstract class GraphAlgorithm<T> {
/** /**
* Gibt an, ob eine Kante passierbar ist. * Gibt an, ob eine Kante passierbar ist.
*
* @param edge Eine Kante * @param edge Eine Kante
* @return true, wenn die Kante passierbar ist. * @return true, wenn die Kante passierbar ist.
*/ */
protected abstract boolean isPassable(Edge<T> edge); protected abstract boolean isPassable(Edge<T> edge);
/** /**
* Gibt an, ob eine Knoten passierbar ist. * Gibt an, ob ein Knoten passierbar ist.
* @param node Eine Knoten *
* @param node Ein Knoten
* @return true, wenn der Knoten passierbar ist. * @return true, wenn der Knoten passierbar ist.
*/ */
protected abstract boolean isPassable(Node<T> node); protected abstract boolean isPassable(Node<T> node);

View file

@ -90,7 +90,9 @@
\begin{itemize} \begin{itemize}
\item HashSet wird verwendet, um die bisher \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 \item ArrayDeque wird verwendet, um die nächsten
Knoten, die besucht werden, zu speichern. Knoten, die besucht werden, zu speichern.
\end{itemize} \end{itemize}