From 1a1d1409f5e35361b6a4e5be9d60f0260fda2f7f Mon Sep 17 00:00:00 2001 From: "J. Neugebauer" Date: Tue, 26 Jan 2021 14:18:11 +0100 Subject: [PATCH] Initial commit --- .gitignore | 26 ++++ Dijkstra.java | 235 ++++++++++++++++++++++++++++++++++ Edge.java | 75 +++++++++++ Graph.java | 312 +++++++++++++++++++++++++++++++++++++++++++++ List.java | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++ Vertex.java | 77 +++++++++++ package.bluej | 59 +++++++++ 7 files changed, 1129 insertions(+) create mode 100644 .gitignore create mode 100644 Dijkstra.java create mode 100644 Edge.java create mode 100644 Graph.java create mode 100644 List.java create mode 100644 Vertex.java create mode 100644 package.bluej diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9fe8940 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# ---> Java +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt +Dokumente* + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + diff --git a/Dijkstra.java b/Dijkstra.java new file mode 100644 index 0000000..f897657 --- /dev/null +++ b/Dijkstra.java @@ -0,0 +1,235 @@ +public class Dijkstra { + + private Graph graph; + + private boolean verbose; + + /** + * Implementierung des Dijkstra-Algorithmus auf ungerichteten, + * gewichteten Grapen. + */ + public Dijkstra() { + graph = new Graph(); + verbose = false; + } + + /** + * Schaltet die ausführliche Ausgabe ein bzw. aus. + */ + public void toggleVerbose() { + verbose = !verbose; + } + + /** + * Erstellt einen Testgraphen und führt den Algorithmus für die Strecke + * Münster -> Lünen aus. + */ + public void test() { + System.out.println("Creating graph.."); + createGraphExample1(); + System.out.println("Searching for shortest path.."); + List path = findShortestPath("Münster", "Lünen"); + //List path = findShortestPath("Haltern", "Münster"); + System.out.println(); + System.out.println("Result:"); + printPath(path); + } + + /** + * Führt den Dijkstra-Algorithmus von einem Startknoten aus und bricht ab, + * sobald der kürzeste Weg zum Zielknoten gefunden wurde. + * + * Der kürzeste Weg wird als Liste von Knoten zurückgegeben. Der kürzeste + * Weg zu den Knoten (auf dem Weg) wird im Attribut {@link Vertex#getValue() value} + * der Knoten gespeichert. + * + * @param from Startknoten + * @param to Endknoten + */ + public List findShortestPath( String from, String to ) { + Vertex start = graph.getVertex(from); + Vertex end = graph.getVertex(to); + + // Markierungen zeigen an, ob ein Knoten schon in die + // Liste einsortiert wurde + graph.setAllEdgeMarks(false); + + List vList = new List<>(); + // Startknoten kommt als Erster in der Liste, + // mit Weglänge 0.0 + start.setValue(0.0); + start.setMark(true); + vList.append(start); + + while( !vList.isEmpty() ) { + Vertex current = findMinVertex(vList); + if( verbose ) + System.out.println("Current node: " + current.getID()); + if( current.equals(end) ) { + // Kürzester Weg für den Zielknoten gefunden + // Können abbrechen + if( verbose ) + System.out.println(" Vertex found; breaking loop"); + break; + } + + List neighbours = graph.getNeighbours(current); + neighbours.toFirst(); + while( neighbours.hasAccess() ) { + Vertex v = neighbours.getContent(); + Edge e = graph.getEdge(current, v); + + if( verbose ) + System.out.println(" Checking neighbour: " + v.getID()); + + if( current.getValue() + e.getWeight() < v.getValue() ) { + // Es wurde ein kürzerer Weg gefunden + // Der Knoten wird aktualisiert + if( verbose ) { + if (v.getValue() == Integer.MAX_VALUE) { + System.out.printf(" Shorter path found: %.2f < Infinity\n", current.getValue() + e.getWeight(), v.getValue()); + } else { + System.out.printf(" Shorter path found: %.2f < %.2f\n", current.getValue() + e.getWeight(), v.getValue()); + } + } + + v.setValue(current.getValue() + e.getWeight()); + v.setPredecessor(current); + } else { + // Kein kürzerer Weg gefunden + if( verbose ) + System.out.printf(" No update: %.2f <= %.2f\n", v.getValue(), current.getValue() + e.getWeight()); + } + if( !v.isMarked() ) { + // Der Knoten muss noch in die Liste einsortiert werden. + v.setMark(true); + vList.append(v); + if( verbose ) + System.out.println(" Added node to list."); + } + + neighbours.next(); + } + } + + return generatePath(end); + } + + /** + * Sucht den Vertex mit dem geringsten Wert aus der Liste, entfernt ihn + * und gibt den Vertex zurück. + * @param pList + * @return + */ + private Vertex findMinVertex( List pList ) { + // Knoten mit kleinstem Wert suchen + pList.toFirst(); + Vertex min = pList.getContent(); + pList.next(); + while( pList.hasAccess() ) { + if (pList.getContent().getValue() < min.getValue() ) { + min = pList.getContent(); + } + pList.next(); + } + // Knoten wieder suchen und entfernen + pList.toFirst(); + while( !pList.getContent().equals(min) ) { + pList.next(); + } + pList.remove(); + // Fertig + return min; + } + + /** + * Erzeugt nach Ablauf des Algorithmus den Weg zu einem + * Knoten aus den {@link Vertex#getPredecessor() predecessor} Attributen + * der Knoten. + * + * @param pVertex + * @return + */ + public List generatePath( Vertex pVertex ) { + List shortestpath = new List<>(); + double length = 0.0; + Vertex current = pVertex; + while( current != null ) { + shortestpath.insert(current); + shortestpath.toFirst(); + current = current.getPredecessor(); + } + + return shortestpath; + } + + /** + * Gibt einen Pfad aus, der in Form einer Liste von Knoten vorliegt. Es + * wird davon ausgegangen, dass die Knoten einen zusammenhängenden Pfad + * darstellen. Ob jeweils Kanten zwischen den Folgeknoten vorliegen wird + * nicht geprüft. + * @param pPath + */ + public void printPath( List pPath ) { + double length = 0.0; + + pPath.toFirst(); + while(pPath.hasAccess()) { + System.out.println("- " + pPath.getContent().getID()); + length = pPath.getContent().getValue(); + pPath.next(); + } + + System.out.printf("Length of shortest path: %.2f\n", length); + } + + public void createGraphExample1() { + graph = new Graph(); + + String[] ids = new String[]{ + "Münster", "Hamm", "Dülmen", + "Haltern", "Lüdinghsn", "Werne", "Lünen", "Kamen", + "y", "x", "3", "79", "80" + }; + Vertex[] v = new Vertex[ids.length]; + for( int i = 0; i < ids.length; i++ ) { + v[i] = new Vertex(ids[i]); + graph.addVertex(v[i]); + } + + graph.addEdge(new Edge(v[0], v[1], 40.0)); + graph.addEdge(new Edge(v[0], v[11], 24.0)); + graph.addEdge(new Edge(v[0], v[5], 37.0)); + graph.addEdge(new Edge(v[0], v[9], 8.0)); + graph.addEdge(new Edge(v[0], v[8], 13.0)); + + graph.addEdge(new Edge(v[1], v[7], 17.0)); + graph.addEdge(new Edge(v[1], v[6], 24.0)); + graph.addEdge(new Edge(v[1], v[11], 24.0)); + + graph.addEdge(new Edge(v[2], v[8], 31.0)); + graph.addEdge(new Edge(v[2], v[3], 12.0)); + + graph.addEdge(new Edge(v[3], v[4], 20.0)); + + graph.addEdge(new Edge(v[4], v[10], 16.0)); + graph.addEdge(new Edge(v[4], v[11], 15.0)); + graph.addEdge(new Edge(v[4], v[6], 21.0)); + + graph.addEdge(new Edge(v[5], v[12], 5.0)); + graph.addEdge(new Edge(v[5], v[6], 10.0)); + + graph.addEdge(new Edge(v[6], v[8], 12.0)); + + graph.addEdge(new Edge(v[8], v[10], 1.0)); + + graph.addEdge(new Edge(v[9], v[10], 4.0)); + graph.addEdge(new Edge(v[9], v[11], 15.0)); + + graph.addEdge(new Edge(v[11], v[12], 11.0)); + } + + + + +} diff --git a/Edge.java b/Edge.java new file mode 100644 index 0000000..1d33776 --- /dev/null +++ b/Edge.java @@ -0,0 +1,75 @@ +/** + *

+ * Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018 + *

+ *

+ * Klasse Edge + *

+ *

+ * Die Klasse Edge stellt eine einzelne, ungerichtete Kante eines Graphen dar. + * Beim Erstellen werden die beiden durch sie zu verbindenden Knotenobjekte und eine + * Gewichtung als double uebergeben. Beide Knotenobjekte koennen abgefragt werden. + * Des Weiteren koennen die Gewichtung und eine Markierung gesetzt und abgefragt werden. + *

+ * + * @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule + * @version Oktober 2015 + */ +public class Edge{ + private Vertex[] vertices; + private double weight; + private boolean mark; + + /** + * Ein neues Objekt vom Typ Edge wird erstellt. Die von diesem Objekt + * repraesentierte Kante verbindet die Knoten pVertex und pAnotherVertex mit der + * Gewichtung pWeight. Ihre Markierung hat den Wert false. + */ + public Edge(Vertex pVertex, Vertex pAnotherVertex, double pWeight){ + vertices = new Vertex[2]; + vertices[0] = pVertex; + vertices[1] = pAnotherVertex; + weight = pWeight; + mark = false; + } + + /** + * Die Anfrage gibt die beiden Knoten, die durch die Kante verbunden werden, als neues Feld vom Typ Vertex zurueck. Das Feld hat + * genau zwei Eintraege mit den Indexwerten 0 und 1. + */ + public Vertex[] getVertices(){ + Vertex[] result = new Vertex[2]; + result[0] = vertices[0]; + result[1] = vertices[1]; + return result; + } + + /** + * Der Auftrag setzt das Gewicht der Kante auf pWeight. + */ + public void setWeight(double pWeight){ + weight = pWeight; + } + + /** + * Die Anfrage liefert das Gewicht der Kante als double. + */ + public double getWeight(){ + return weight; + } + + /** + * Der Auftrag setzt die Markierung der Kante auf den Wert pMark. + */ + public void setMark(boolean pMark){ + mark = pMark; + } + + /** + * Die Anfrage liefert true, wenn die Markierung der Kante den Wert true hat, ansonsten false. + */ + public boolean isMarked(){ + return mark; + } + +} diff --git a/Graph.java b/Graph.java new file mode 100644 index 0000000..43a8109 --- /dev/null +++ b/Graph.java @@ -0,0 +1,312 @@ +/** + *

+ * Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018 + *

+ *

+ * Klasse Graph + *

+ *

+ * Die Klasse Graph stellt einen ungerichteten, kantengewichteten Graphen dar. Es koennen + * Knoten- und Kantenobjekte hinzugefuegt und entfernt, flache Kopien der Knoten- und Kantenlisten + * des Graphen angefragt und Markierungen von Knoten und Kanten gesetzt und ueberprueft werden. + * Des Weiteren kann eine Liste der Nachbarn eines bestimmten Knoten, eine Liste der inzidenten + * Kanten eines bestimmten Knoten und die Kante von einem bestimmten Knoten zu einem + * anderen bestimmten Knoten angefragt werden. Abgesehen davon kann abgefragt werden, welches + * Knotenobjekt zu einer bestimmten ID gehoert und ob der Graph leer ist. + *

+ * + * @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule + * @version Oktober 2015 + */ +public class Graph{ + private List vertices; + private List edges; + + /** + * Ein Objekt vom Typ Graph wird erstellt. Der von diesem Objekt + * repraesentierte Graph ist leer. + */ + public Graph(){ + //Leere Listen fuer Knoten und Kanten erstellen. + vertices = new List(); + edges = new List(); + } + + /** + * Die Anfrage liefert eine neue Liste aller Knotenobjekte vom Typ List. + */ + public List getVertices(){ + //Eine neue Liste mit allen Vertex-Objekten erstellen. + List result = new List(); + vertices.toFirst(); + while (vertices.hasAccess()){ + result.append(vertices.getContent()); + vertices.next(); + } + //Aktuelles Element zum Anfang bewegen. + result.toFirst(); + + return result; + } + + /** + * Die Anfrage liefert eine neue Liste aller Kantenobjekte vom Typ List. + */ + public List getEdges(){ + //Eine neue Liste mit allen Edge-Objekten erstellen. + List result = new List(); + edges.toFirst(); + while (edges.hasAccess()){ + result.append(edges.getContent()); + edges.next(); + } + //Aktuelles Element zum Anfang bewegen. + result.toFirst(); + + return result; + } + + /** + * Die Anfrage liefert das Knotenobjekt mit pID als ID. Ist ein solchen Knotenobjekt nicht im Graphen enthalten, + * wird null zurueckgeliefert. + */ + public Vertex getVertex(String pID){ + //Vertex-Objekt mit pID als ID suchen. + Vertex result = null; + vertices.toFirst(); + while (vertices.hasAccess() && result == null){ + if (vertices.getContent().getID().equals(pID)){ + result = vertices.getContent(); + } + vertices.next(); + } + + //Objekt zurueckliefern. + return result; + } + + /** + * Der Auftrag fuegt den Knoten pVertex in den Graphen ein, sofern es noch keinen + * Knoten mit demselben ID-Eintrag wie pVertex im Graphen gibt und pVertex eine ID ungleich null hat. + * Ansonsten passiert nichts. + */ + public void addVertex(Vertex pVertex){ + //Pruefen, ob der Vertex existiert und eine ID hat. + if (pVertex != null && pVertex.getID() != null) { + //Pruefen, ob nicht schon ein Vertex mit gleicher ID enthalten ist. + boolean freeID = true; + vertices.toFirst(); + while (vertices.hasAccess() && freeID){ + if (vertices.getContent().getID().equals(pVertex.getID())){ + freeID = false; + } + vertices.next(); + } + + //Wenn die ID noch frei ist, den Vertex einfuegen, sonst nichts tun. + if (freeID) { + vertices.append(pVertex); + } + } + } + + /** + * Der Auftrag fuegt die Kante pEdge in den Graphen ein, sofern beide durch die Kante verbundenen Knoten + * im Graphen enthalten sind, nicht identisch sind und noch keine Kante zwischen den Knoten existiert. Ansonsten passiert nichts. + */ + public void addEdge(Edge pEdge){ + //Pruefen, ob pEdge exisitert. + if (pEdge != null){ + Vertex[] vertexPair = pEdge.getVertices(); + + //Einfuegekriterien pruefen. + if (vertexPair[0] != null && vertexPair[1] != null && + this.getVertex(vertexPair[0].getID()) == vertexPair[0] && + this.getVertex(vertexPair[1].getID()) == vertexPair[1] && + this.getEdge(vertexPair[0], vertexPair[1]) == null && + vertexPair[0] != vertexPair[1]){ + //Kante einfuegen. + edges.append(pEdge); + } + } + } + + /** + * Der Auftrag entfernt den Knoten pVertex aus dem Graphen und loescht alle Kanten, die mit ihm inzident sind. + * Ist der Knoten pVertex nicht im Graphen enthalten, passiert nichts. + */ + public void removeVertex(Vertex pVertex){ + //Inzidente Kanten entfernen. + edges.toFirst(); + while (edges.hasAccess()){ + Vertex[] akt = edges.getContent().getVertices(); + if (akt[0] == pVertex || akt[1] == pVertex){ + edges.remove(); + } else { + edges.next(); + } + } + + //Knoten entfernen + vertices.toFirst(); + while (vertices.hasAccess() && vertices.getContent()!= pVertex){ + vertices.next(); + } + if (vertices.hasAccess()){ + vertices.remove(); + } + } + + /** + * Der Auftrag entfernt die Kante pEdge aus dem Graphen. Ist die Kante pEdge nicht + * im Graphen enthalten, passiert nichts. + */ + public void removeEdge(Edge pEdge){ + //Kante aus Kantenliste des Graphen entfernen. + edges.toFirst(); + while (edges.hasAccess()){ + if (edges.getContent() == pEdge){ + edges.remove(); + } else { + edges.next(); + } + } + } + + /** + * Der Auftrag setzt die Markierungen aller Knoten des Graphen auf pMark. + */ + public void setAllVertexMarks(boolean pMark){ + vertices.toFirst(); + while (vertices.hasAccess()){ + vertices.getContent().setMark(pMark); + vertices.next(); + } + } + + /** + * Der Auftrag setzt die Markierungen aller Kanten des Graphen auf pMark. + */ + public void setAllEdgeMarks(boolean pMark){ + edges.toFirst(); + while (edges.hasAccess()){ + edges.getContent().setMark(pMark); + edges.next(); + } + } + + /** + * Die Anfrage liefert true, wenn alle Knoten des Graphen mit true markiert sind, ansonsten false. + */ + public boolean allVerticesMarked(){ + boolean result = true; + vertices.toFirst(); + while (vertices.hasAccess()){ + if (!vertices.getContent().isMarked()){ + result = false; + } + vertices.next(); + } + return result; + } + + /** + * Die Anfrage liefert true, wenn alle Kanten des Graphen mit true markiert sind, ansonsten false. + */ + public boolean allEdgesMarked(){ + boolean result = true; + edges.toFirst(); + while (edges.hasAccess()){ + if (!edges.getContent().isMarked()){ + result = false; + } + edges.next(); + } + return result; + } + + /** + * Die Anfrage liefert alle Nachbarn des Knotens pVertex als neue Liste vom Typ List. Hat der Knoten + * pVertex keine Nachbarn in diesem Graphen oder ist gar nicht in diesem Graphen enthalten, so + * wird eine leere Liste zurueckgeliefert. + */ + public List getNeighbours(Vertex pVertex){ + List result = new List(); + + //Alle Kanten durchlaufen. + edges.toFirst(); + while (edges.hasAccess()){ + + //Wenn ein Knoten der Kante pVertex ist, den anderen als Nachbarn in die Ergebnisliste einfuegen. + Vertex[] vertexPair = edges.getContent().getVertices(); + if (vertexPair[0] == pVertex) { + result.append(vertexPair[1]); + } else { + if (vertexPair[1] == pVertex){ + result.append(vertexPair[0]); + } + } + edges.next(); + } + return result; + } + + /** + * Die Anfrage liefert eine neue Liste alle inzidenten Kanten zum Knoten pVertex. Hat der Knoten + * pVertex keine inzidenten Kanten in diesem Graphen oder ist gar nicht in diesem Graphen enthalten, so + * wird eine leere Liste zurueckgeliefert. + */ + public List getEdges(Vertex pVertex){ + List result = new List(); + + //Alle Kanten durchlaufen. + edges.toFirst(); + while (edges.hasAccess()){ + + //Wenn ein Knoten der Kante pVertex ist, dann Kante als inzidente Kante in die Ergebnisliste einfuegen. + Vertex[] vertexPair = edges.getContent().getVertices(); + if (vertexPair[0] == pVertex) { + result.append(edges.getContent()); + } else{ + if (vertexPair[1] == pVertex){ + result.append(edges.getContent()); + } + } + edges.next(); + } + return result; + } + + /** + * Die Anfrage liefert die Kante, welche die Knoten pVertex und pAnotherVertex verbindet, + * als Objekt vom Typ Edge. Ist der Knoten pVertex oder der Knoten pAnotherVertex nicht + * im Graphen enthalten oder gibt es keine Kante, die beide Knoten verbindet, so wird null + * zurueckgeliefert. + */ + public Edge getEdge(Vertex pVertex, Vertex pAnotherVertex){ + Edge result = null; + + //Kanten durchsuchen, solange keine passende gefunden wurde. + edges.toFirst(); + while (edges.hasAccess() && result == null){ + + //Pruefen, ob die Kante pVertex und pAnotherVertex verbindet. + Vertex[] vertexPair = edges.getContent().getVertices(); + if ((vertexPair[0] == pVertex && vertexPair[1] == pAnotherVertex) || + (vertexPair[0] == pAnotherVertex && vertexPair[1] == pVertex)) { + //Kante als Ergebnis merken. + result = edges.getContent(); + } + edges.next(); + } + return result; + } + + /** + * Die Anfrage liefert true, wenn der Graph keine Knoten enthaelt, ansonsten false. + */ + public boolean isEmpty(){ + return vertices.isEmpty(); + } + +} diff --git a/List.java b/List.java new file mode 100644 index 0000000..8c82b92 --- /dev/null +++ b/List.java @@ -0,0 +1,345 @@ + /** + *

+ * Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018 + *

+ *

+ * Generische Klasse List + *

+ *

+ * Objekt der generischen Klasse List verwalten beliebig viele linear + * angeordnete Objekte vom Typ ContentType. Auf hoechstens ein Listenobjekt, + * aktuellesObjekt genannt, kann jeweils zugegriffen werden.
+ * Wenn eine Liste leer ist, vollstaendig durchlaufen wurde oder das aktuelle + * Objekt am Ende der Liste geloescht wurde, gibt es kein aktuelles Objekt.
+ * Das erste oder das letzte Objekt einer Liste koennen durch einen Auftrag zum + * aktuellen Objekt gemacht werden. Ausserdem kann das dem aktuellen Objekt + * folgende Listenobjekt zum neuen aktuellen Objekt werden.
+ * Das aktuelle Objekt kann gelesen, veraendert oder geloescht werden. Ausserdem + * kann vor dem aktuellen Objekt ein Listenobjekt eingefuegt werden. + *

+ * + * @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule + * @version Generisch_06 2015-10-25 + */ +public class List { + + /* --------- Anfang der privaten inneren Klasse -------------- */ + + private class ListNode { + + private ContentType contentObject; + private ListNode next; + + /** + * Ein neues Objekt wird erschaffen. Der Verweis ist leer. + * + * @param pContent das Inhaltsobjekt vom Typ ContentType + */ + private ListNode(ContentType pContent) { + contentObject = pContent; + next = null; + } + + /** + * Der Inhalt des Knotens wird zurueckgeliefert. + * + * @return das Inhaltsobjekt des Knotens + */ + public ContentType getContentObject() { + return contentObject; + } + + /** + * Der Inhalt dieses Kontens wird gesetzt. + * + * @param pContent das Inhaltsobjekt vom Typ ContentType + */ + public void setContentObject(ContentType pContent) { + contentObject = pContent; + } + + /** + * Der Nachfolgeknoten wird zurueckgeliefert. + * + * @return das Objekt, auf das der aktuelle Verweis zeigt + */ + public ListNode getNextNode() { + return this.next; + } + + /** + * Der Verweis wird auf das Objekt, das als Parameter uebergeben + * wird, gesetzt. + * + * @param pNext der Nachfolger des Knotens + */ + public void setNextNode(ListNode pNext) { + this.next = pNext; + } + + } + + /* ----------- Ende der privaten inneren Klasse -------------- */ + + // erstes Element der Liste + ListNode first; + + // letztes Element der Liste + ListNode last; + + // aktuelles Element der Liste + ListNode current; + + /** + * Eine leere Liste wird erzeugt. + */ + public List() { + first = null; + last = null; + current = null; + } + + /** + * Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthaelt, + * sonst liefert sie den Wert false. + * + * @return true, wenn die Liste leer ist, sonst false + */ + public boolean isEmpty() { + // Die Liste ist leer, wenn es kein erstes Element gibt. + return first == null; + } + + /** + * Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, + * sonst liefert sie den Wert false. + * + * @return true, falls Zugriff moeglich, sonst false + */ + public boolean hasAccess() { + // Es gibt keinen Zugriff, wenn current auf kein Element verweist. + return current != null; + } + + /** + * Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses + * nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in + * der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach + * Ausfuehrung des Auftrags kein aktuelles Objekt, d.h. hasAccess() liefert + * den Wert false. + */ + public void next() { + if (this.hasAccess()) { + current = current.getNextNode(); + } + } + + /** + * Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles + * Objekt. Ist die Liste leer, geschieht nichts. + */ + public void toFirst() { + if (!isEmpty()) { + current = first; + } + } + + /** + * Falls die Liste nicht leer ist, wird das letzte Objekt der Liste + * aktuelles Objekt. Ist die Liste leer, geschieht nichts. + */ + public void toLast() { + if (!isEmpty()) { + current = last; + } + } + + /** + * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das + * aktuelle Objekt zurueckgegeben, andernfalls (hasAccess() == false) gibt + * die Anfrage den Wert null zurueck. + * + * @return das aktuelle Objekt (vom Typ ContentType) oder null, wenn es + * kein aktuelles Objekt gibt + */ + public ContentType getContent() { + if (this.hasAccess()) { + return current.getContentObject(); + } else { + return null; + } + } + + /** + * Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent + * ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst + * geschieht nichts. + * + * @param pContent + * das zu schreibende Objekt vom Typ ContentType + */ + public void setContent(ContentType pContent) { + // Nichts tun, wenn es keinen Inhalt oder kein aktuelles Element gibt. + if (pContent != null && this.hasAccess()) { + current.setContentObject(pContent); + } + } + + /** + * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues + * Objekt vor dem aktuellen Objekt in die Liste eingefuegt. Das aktuelle + * Objekt bleibt unveraendert.
+ * Wenn die Liste leer ist, wird pContent in die Liste eingefuegt und es + * gibt weiterhin kein aktuelles Objekt (hasAccess() == false).
+ * Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste + * nicht leer ist oder pContent gleich null ist, geschieht nichts. + * + * @param pContent + * das einzufuegende Objekt vom Typ ContentType + */ + public void insert(ContentType pContent) { + if (pContent != null) { // Nichts tun, wenn es keinen Inhalt gibt. + if (this.hasAccess()) { // Fall: Es gibt ein aktuelles Element. + + // Neuen Knoten erstellen. + ListNode newNode = new ListNode(pContent); + + if (current != first) { // Fall: Nicht an erster Stelle einfuegen. + ListNode previous = this.getPrevious(current); + newNode.setNextNode(previous.getNextNode()); + previous.setNextNode(newNode); + } else { // Fall: An erster Stelle einfuegen. + newNode.setNextNode(first); + first = newNode; + } + + } else { //Fall: Es gibt kein aktuelles Element. + + if (this.isEmpty()) { // Fall: In leere Liste einfuegen. + + // Neuen Knoten erstellen. + ListNode newNode = new ListNode(pContent); + + first = newNode; + last = newNode; + } + + } + } + } + + /** + * Falls pContent gleich null ist, geschieht nichts.
+ * Ansonsten wird ein neues Objekt pContent am Ende der Liste eingefuegt. + * Das aktuelle Objekt bleibt unveraendert.
+ * Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefuegt + * und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). + * + * @param pContent + * das anzuhaengende Objekt vom Typ ContentType + */ + public void append(ContentType pContent) { + if (pContent != null) { // Nichts tun, wenn es keine Inhalt gibt. + + if (this.isEmpty()) { // Fall: An leere Liste anfuegen. + this.insert(pContent); + } else { // Fall: An nicht-leere Liste anfuegen. + + // Neuen Knoten erstellen. + ListNode newNode = new ListNode(pContent); + + last.setNextNode(newNode); + last = newNode; // Letzten Knoten aktualisieren. + } + + } + } + + /** + * Falls es sich bei der Liste und pList um dasselbe Objekt handelt, + * pList null oder eine leere Liste ist, geschieht nichts.
+ * Ansonsten wird die Liste pList an die aktuelle Liste angehaengt. + * Anschliessend wird pList eine leere Liste. Das aktuelle Objekt bleibt + * unveraendert. Insbesondere bleibt hasAccess identisch. + * + * @param pList + * die am Ende anzuhaengende Liste vom Typ List + */ + public void concat(List pList) { + if (pList != this && pList != null && !pList.isEmpty()) { // Nichts tun, + // wenn pList und this identisch, pList leer oder nicht existent. + + if (this.isEmpty()) { // Fall: An leere Liste anfuegen. + this.first = pList.first; + this.last = pList.last; + } else { // Fall: An nicht-leere Liste anfuegen. + this.last.setNextNode(pList.first); + this.last = pList.last; + } + + // Liste pList loeschen. + pList.first = null; + pList.last = null; + pList.current = null; + } + } + + /** + * Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() + * == false), geschieht nichts.
+ * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das + * aktuelle Objekt geloescht und das Objekt hinter dem geloeschten Objekt + * wird zum aktuellen Objekt.
+ * Wird das Objekt, das am Ende der Liste steht, geloescht, gibt es kein + * aktuelles Objekt mehr. + */ + public void remove() { + // Nichts tun, wenn es kein aktuelle Element gibt oder die Liste leer ist. + if (this.hasAccess() && !this.isEmpty()) { + + if (current == first) { + first = first.getNextNode(); + } else { + ListNode previous = this.getPrevious(current); + if (current == last) { + last = previous; + } + previous.setNextNode(current.getNextNode()); + } + + ListNode temp = current.getNextNode(); + current.setContentObject(null); + current.setNextNode(null); + current = temp; + + //Beim loeschen des letzten Elements last auf null setzen. + if (this.isEmpty()) { + last = null; + } + } + } + + /** + * Liefert den Vorgaengerknoten des Knotens pNode. Ist die Liste leer, pNode + * == null, pNode nicht in der Liste oder pNode der erste Knoten der Liste, + * wird null zurueckgegeben. + * + * @param pNode + * der Knoten, dessen Vorgaenger zurueckgegeben werden soll + * @return der Vorgaenger des Knotens pNode oder null, falls die Liste leer ist, + * pNode == null ist, pNode nicht in der Liste ist oder pNode der erste Knoten + * der Liste ist + */ + private ListNode getPrevious(ListNode pNode) { + if (pNode != null && pNode != first && !this.isEmpty()) { + ListNode temp = first; + while (temp != null && temp.getNextNode() != pNode) { + temp = temp.getNextNode(); + } + return temp; + } else { + return null; + } + } + +} diff --git a/Vertex.java b/Vertex.java new file mode 100644 index 0000000..5fd1f66 --- /dev/null +++ b/Vertex.java @@ -0,0 +1,77 @@ +/** + *

+ * Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018 + *

+ *

+ * Klasse Vertex + *

+ *

+ * Die Klasse Vertex stellt einen einzelnen Knoten eines Graphen dar. Jedes Objekt + * dieser Klasse verfuegt ueber eine im Graphen eindeutige ID als String und kann diese + * ID zurueckliefern. Darueber hinaus kann eine Markierung gesetzt und abgefragt werden. + *

+ * + * @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule + * @version Oktober 2015 + */ +public class Vertex{ + //Einmalige ID des Knotens und Markierung + private String id; + private boolean mark; + + // Ergänzugnen für Dijkstra + // Speicher für den kürzesten Weg + private double value; + // Vorgängenknoten im kürzesten Weg + private Vertex predecessor; + + /** + * Ein neues Objekt vom Typ Vertex wird erstellt. Seine Markierung hat den Wert false. + */ + public Vertex(String pID){ + id = pID; + mark = false; + value = Integer.MAX_VALUE; + predecessor = null; + } + + /** + * Die Anfrage liefert die ID des Knotens als String. + */ + public String getID(){ + return new String(id); + } + + /** + * Der Auftrag setzt die Markierung des Knotens auf den Wert pMark. + */ + public void setMark(boolean pMark){ + mark = pMark; + } + + /** + * Die Anfrage liefert true, wenn die Markierung des Knotens den Wert true hat, ansonsten false. + */ + public boolean isMarked(){ + return mark; + } + + + public double getValue() { + return value; + } + + public void setValue(double value) { + this.value = value; + } + + public Vertex getPredecessor() { + return predecessor; + } + + public void setPredecessor(Vertex predecessor) { + this.predecessor = predecessor; + } + + +} diff --git a/package.bluej b/package.bluej new file mode 100644 index 0000000..677f390 --- /dev/null +++ b/package.bluej @@ -0,0 +1,59 @@ +#BlueJ package file +dependency1.from=BinarySearchTree +dependency1.to=ComparableContent +dependency1.type=UsesDependency +dependency2.from=Racingsimulator +dependency2.to=Athlete +dependency2.type=UsesDependency +editor.fx.0.height=738 +editor.fx.0.width=816 +editor.fx.0.x=466 +editor.fx.0.y=146 +objectbench.height=100 +objectbench.width=1256 +package.divider.horizontal=0.6 +package.divider.vertical=0.881243063263041 +package.editor.height=787 +package.editor.width=1145 +package.editor.x=0 +package.editor.y=0 +package.frame.height=1000 +package.frame.width=1296 +package.numDependencies=2 +package.numTargets=4 +package.showExtends=true +package.showUses=true +project.charset=UTF-8 +readme.height=58 +readme.name=@README +readme.width=47 +readme.x=10 +readme.y=10 +target1.height=50 +target1.name=Racingsimulator +target1.showInterface=false +target1.type=ClassTarget +target1.width=130 +target1.x=450 +target1.y=472 +target2.height=50 +target2.name=ComparableContent +target2.showInterface=false +target2.type=InterfaceTarget +target2.width=250 +target2.x=160 +target2.y=270 +target3.height=50 +target3.name=Athlete +target3.showInterface=false +target3.type=ClassTarget +target3.width=90 +target3.x=280 +target3.y=550 +target4.height=50 +target4.name=BinarySearchTree +target4.showInterface=false +target4.type=ClassTarget +target4.width=230 +target4.x=370 +target4.y=90