From fe59c35d59495d4eecbbe307064ce73f2d4f7315 Mon Sep 17 00:00:00 2001 From: Jonas Neugebauer Date: Fri, 15 Jan 2021 13:08:53 +0100 Subject: [PATCH] Initial commit --- Breitensuche.java | 153 +++++++++++++++++++ BreitensucheTest.java | 25 +++ Edge.java | 75 +++++++++ Graph.java | 312 ++++++++++++++++++++++++++++++++++++++ List.java | 345 ++++++++++++++++++++++++++++++++++++++++++ Queue.java | 142 +++++++++++++++++ Vertex.java | 51 +++++++ package.bluej | 59 ++++++++ 8 files changed, 1162 insertions(+) create mode 100644 Breitensuche.java create mode 100644 BreitensucheTest.java create mode 100644 Edge.java create mode 100644 Graph.java create mode 100644 List.java create mode 100644 Queue.java create mode 100644 Vertex.java create mode 100644 package.bluej diff --git a/Breitensuche.java b/Breitensuche.java new file mode 100644 index 0000000..f1e2461 --- /dev/null +++ b/Breitensuche.java @@ -0,0 +1,153 @@ + +/** + * Implementierung der Tiefensuche auf einem ungereichteten, + * gewichteten Graphen. + */ +public class Breitensuche { + + private Graph g; + + public Breitensuche() { + g = new Graph(); + + // Aufbau des Graphen + // Erstellen der Knoten (Vertices) + Vertex koe = new Vertex("Köln"); + g.addVertex(koe); + Vertex dues = new Vertex("Düsseldorf"); + g.addVertex(dues); + Vertex dor = new Vertex("Dortmund"); + g.addVertex(dor); + Vertex bi = new Vertex("Bielefeld"); + g.addVertex(bi); + Vertex hnv = new Vertex("Hannover"); + g.addVertex(hnv); + Vertex bo = new Vertex("Bochum"); + g.addVertex(bo); + + // Erstellen der Kanten (Edges) + g.addEdge(new Edge(koe, dor, 96.0)); + g.addEdge(new Edge(dues, dor, 70.0)); + g.addEdge(new Edge(dor, bo, 22.0)); + g.addEdge(new Edge(bi, hnv, 113.0)); + g.addEdge(new Edge(bi, dor, 112.0)); + g.addEdge(new Edge(bi, dues, 178.0)); + g.addEdge(new Edge(bo, dues, 52.0)); + } + + /** + * Suche nach einem Vertex mit der angegebenen ID mittels der Breitensuche. + * @param pVertexID + * @return + */ + public boolean findVertex( String pVertexID ) { + g.setAllVertexMarks(false); // Markierungen zurücksetzen + Queue searchQueue = new Queue<>(); // Speicher für zu bearbeitende Knoten erstellen + + // TODO: Implementiere die Breitensuche als iterativen Algorithmus: + // Reihe dazu die noch nicht markierten Nachbarknoten in die + // searchQueue ein und arbeite die Knoten in ihr der Reihe nach + // ab, bis die Queue leer ist, oder der gesuchte Knoten + // gefunden wurde. + // TODO: Ergänze deine Methode um Ausgaben, anhand derer die Abarbeitung + // deutlich wird. + // TODO: Wenn dein Algorithmus funnktioniert, kopiere die Methode und + // Erstelle Varianten, bei denen die Reihenfolge der Nachbarknoten + // modifiziert ist. Dazu + return false; + } + + /** + * + * @param pVertexID + * @return + */ + public boolean findVertexByID( String pVertexID ) { + g.setAllVertexMarks(false); // Markierungen zurücksetzen + Queue searchQueue = new Queue<>(); // Speicher für zu bearbeitende Knoten erstellen + + // TODO: Ändere die Breitensuche so ab, dass die Knoten so abgearbeitet + // werden, dass die Nachbarknoten in alphabetischer Reihenfolge + // besucht werden. + // Nutze dazu die Hilfsmethode getVertexFromListByID, um aus + // Liste der Nachbarknoten denjenigen, der alphabetisch als + // erstes kommt herauszusuchen. + return false; + } + + public boolean findVertexByWeight( String pVertexID ) { + g.setAllVertexMarks(false); // Markierungen zurücksetzen + Queue searchQueue = new Queue<>(); // Speicher für zu bearbeitende Knoten erstellen + + // TODO: Ändere die Breitensuche so ab, dass die Knoten so abgearbeitet + // werden, dass der Nachbarknoten mit der Kante mit dem geringsten + // Gewicht zuerst besucht wird. + // Nutze dazu die Hilfsmethode getVertexFromListByWeight, um aus + // Liste der Nachbarknoten denjenigen mit dem geringsten Gewicht + // herauszusuchen. + return false; + } + + + /** + * Sucht aus einer Liste von Knoten denjenigen, dessen ID alphabetisch ale + * erstes kommt. Der Knoten wird aus der Liste gelöscht und dann zurück + * gegeben. + * @param pVertices + * @return + */ + private Vertex getVertexFromListByID( List pVertices ) { + pVertices.toFirst(); + Vertex v = pVertices.getContent(); + do { + pVertices.next(); + + if( pVertices.hasAccess() && + pVertices.getContent().getID().compareToIgnoreCase(v.getID()) < 0 ) { + v = pVertices.getContent(); + } + } while( pVertices.hasAccess() ); + + pVertices.toFirst(); + while( pVertices.hasAccess() ) { + if( pVertices.getContent().getID().equals(v.getID()) ) { + break; + } + pVertices.next(); + } + pVertices.remove(); + return v; + } + + /** + * Sucht aus einer Liste von Knoten denjenigen, dessen Kantengewicht zum + * Konten pCurrentVertex am geringsten ist. Der Knoten wird + * aus der Liste gelöscht und dann zurück + * gegeben. + * @param pVertices + * @return + */ + private Vertex getVertexFromListByWeight( Vertex pCurrentVertex, List pVertices ) { + pVertices.toFirst(); + Vertex v = pVertices.getContent(); + double weight = g.getEdge(pCurrentVertex, v).getWeight(); + do { + pVertices.next(); + + if( pVertices.hasAccess() && + g.getEdge(pCurrentVertex, pVertices.getContent()).getWeight() < weight ) { + v = pVertices.getContent(); + } + } while( pVertices.hasAccess() ); + + pVertices.toFirst(); + while( pVertices.hasAccess() ) { + if( pVertices.getContent().getID().equals(v.getID()) ) { + break; + } + pVertices.next(); + } + pVertices.remove(); + return v; + } +} diff --git a/BreitensucheTest.java b/BreitensucheTest.java new file mode 100644 index 0000000..e073d5a --- /dev/null +++ b/BreitensucheTest.java @@ -0,0 +1,25 @@ +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class BreitensucheTest { + + @Before + public void setUp() { + + } + + @Test + public void testFindVertex() { + Breitensuche ts = new Breitensuche(); + + assertTrue("Der Knoten Köln ist im Graphen vorhanden.", ts.findVertex("Köln")); + assertTrue("Der Knoten Bielefeld ist im Graphen vorhanden.", ts.findVertex("Bielefeld")); + assertTrue("Der Knoten Bochum ist im Graphen vorhanden.", ts.findVertex("Bochum")); + + assertFalse("Der Knoten Tokio ist nicht im Graphen vorhanden.", ts.findVertex("Tokio")); + assertFalse("Der Knoten London ist nicht im Graphen vorhanden.", ts.findVertex("London")); + } + +} 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/Queue.java b/Queue.java new file mode 100644 index 0000000..e7835c0 --- /dev/null +++ b/Queue.java @@ -0,0 +1,142 @@ +/** + *

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

+ *

+ * Generische Klasse Queue + *

+ *

+ * Objekte der generischen Klasse Queue (Warteschlange) verwalten beliebige + * Objekte vom Typ ContentType nach dem First-In-First-Out-Prinzip, d.h., das + * zuerst abgelegte Objekt wird als erstes wieder entnommen. Alle Methoden haben + * eine konstante Laufzeit, unabhaengig von der Anzahl der verwalteten Objekte. + *

+ * + * @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule + * @version Generisch_02 2014-02-21 + */ +public class Queue { + + /* --------- Anfang der privaten inneren Klasse -------------- */ + + private class QueueNode { + + private ContentType content = null; + private QueueNode nextNode = null; + + /** + * Ein neues Objekt vom Typ QueueNode wird erschaffen. + * Der Inhalt wird per Parameter gesetzt. Der Verweis ist leer. + * + * @param pContent das Inhaltselement des Knotens vom Typ ContentType + */ + public QueueNode(ContentType pContent) { + content = pContent; + nextNode = null; + } + + /** + * Der Verweis wird auf das Objekt, das als Parameter uebergeben wird, + * gesetzt. + * + * @param pNext der Nachfolger des Knotens + */ + public void setNext(QueueNode pNext) { + nextNode = pNext; + } + + /** + * Liefert das naechste Element des aktuellen Knotens. + * + * @return das Objekt vom Typ QueueNode, auf das der aktuelle Verweis zeigt + */ + public QueueNode getNext() { + return nextNode; + } + + /** + * Liefert das Inhaltsobjekt des Knotens vom Typ ContentType. + * + * @return das Inhaltsobjekt des Knotens + */ + public ContentType getContent() { + return content; + } + + } + + /* ----------- Ende der privaten inneren Klasse -------------- */ + + private QueueNode head; + private QueueNode tail; + + /** + * Eine leere Schlange wird erzeugt. + * Objekte, die in dieser Schlange verwaltet werden, muessen vom Typ + * ContentType sein. + */ + public Queue() { + head = null; + tail = null; + } + + /** + * Die Anfrage liefert den Wert true, wenn die Schlange keine Objekte enthaelt, + * sonst liefert sie den Wert false. + * + * @return true, falls die Schlange leer ist, sonst false + */ + public boolean isEmpty() { + return head == null; + } + + /** + * Das Objekt pContentType wird an die Schlange angehaengt. + * Falls pContentType gleich null ist, bleibt die Schlange unveraendert. + * + * @param pContent + * das anzuhaengende Objekt vom Typ ContentType + */ + public void enqueue(ContentType pContent) { + if (pContent != null) { + QueueNode newNode = new QueueNode(pContent); + if (this.isEmpty()) { + head = newNode; + tail = newNode; + } else { + tail.setNext(newNode); + tail = newNode; + } + } + } + + /** + * Das erste Objekt wird aus der Schlange entfernt. + * Falls die Schlange leer ist, wird sie nicht veraendert. + */ + public void dequeue() { + if (!this.isEmpty()) { + head = head.getNext(); + if (this.isEmpty()) { + head = null; + tail = null; + } + } + } + + /** + * Die Anfrage liefert das erste Objekt der Schlange. + * Die Schlange bleibt unveraendert. + * Falls die Schlange leer ist, wird null zurueckgegeben. + * + * @return das erste Objekt der Schlange vom Typ ContentType oder null, + * falls die Schlange leer ist + */ + public ContentType front() { + if (this.isEmpty()) { + return null; + } else { + return head.getContent(); + } + } +} diff --git a/Vertex.java b/Vertex.java new file mode 100644 index 0000000..403a08e --- /dev/null +++ b/Vertex.java @@ -0,0 +1,51 @@ +/** + *

+ * 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; + + /** + * Ein neues Objekt vom Typ Vertex wird erstellt. Seine Markierung hat den Wert false. + */ + public Vertex(String pID){ + id = pID; + mark = false; + } + + /** + * 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; + } + +} 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