WIP 3.1.3
This commit is contained in:
parent
6102da73fa
commit
f4eec30656
2 changed files with 182 additions and 121 deletions
|
|
@ -5,13 +5,15 @@ 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 <T> Die Datenstruktur des Graphen
|
||||
*/
|
||||
public abstract class GraphAlgorithm<T> {
|
||||
|
||||
/**
|
||||
* Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern
|
||||
* Sie weist jedem Knoten einen Wert und einen Vorgängerknoten zu.
|
||||
* Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern Sie weist
|
||||
* jedem Knoten einen Wert und einen Vorgängerknoten zu.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
private static class AlgorithmNode<T> {
|
||||
|
|
@ -36,7 +38,9 @@ public abstract class GraphAlgorithm<T> {
|
|||
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 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}.
|
||||
* Sollte kein Knoten gefunden werden, wird null zurückgegeben.
|
||||
* Verbindliche Anforderung: Verwenden Sie beim Durchlaufen der Liste Iteratoren
|
||||
* 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<T> getSmallestNode() {
|
||||
// TODO: GraphAlgorithm<T>#getSmallestNode()
|
||||
if(availableNodes.isEmpty())
|
||||
{
|
||||
|
||||
if (availableNodes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Iterator<Node<T>> iter = availableNodes.iterator();
|
||||
Iterator<Node<T>> iterMinElem = iter;
|
||||
AlgorithmNode<T> MinElem;
|
||||
AlgorithmNode<T> tempElem;
|
||||
if(iter.hasNext())
|
||||
{
|
||||
|
||||
if (iter.hasNext()) {
|
||||
MinElem = algorithmNodes.get(iter.next());
|
||||
while (iter.hasNext())
|
||||
{
|
||||
while (iter.hasNext()) {
|
||||
tempElem = algorithmNodes.get(iter.next());
|
||||
if(tempElem.value < MinElem.value)
|
||||
{
|
||||
if (tempElem.value < MinElem.value) {
|
||||
iterMinElem = iter;
|
||||
MinElem = tempElem;
|
||||
}
|
||||
|
|
@ -82,42 +86,93 @@ public abstract class GraphAlgorithm<T> {
|
|||
iter.remove();
|
||||
return MinElem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
* 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() {
|
||||
// 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.
|
||||
* 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.
|
||||
* 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<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;
|
||||
|
||||
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
|
||||
*
|
||||
* @return der zu betrachtende Graph
|
||||
*/
|
||||
protected Graph<T> getGraph() {
|
||||
|
|
@ -125,8 +180,10 @@ public abstract class GraphAlgorithm<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -134,14 +191,16 @@ public abstract class GraphAlgorithm<T> {
|
|||
|
||||
/**
|
||||
* Gibt an, ob eine Kante passierbar ist.
|
||||
*
|
||||
* @param edge Eine Kante
|
||||
* @return true, wenn die Kante passierbar ist.
|
||||
*/
|
||||
protected abstract boolean isPassable(Edge<T> edge);
|
||||
|
||||
/**
|
||||
* Gibt an, ob eine Knoten passierbar ist.
|
||||
* @param node Eine Knoten
|
||||
* Gibt an, ob ein Knoten passierbar ist.
|
||||
*
|
||||
* @param node Ein Knoten
|
||||
* @return true, wenn der Knoten passierbar ist.
|
||||
*/
|
||||
protected abstract boolean isPassable(Node<T> node);
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue