From 8bce97f6532edbdd412a390d2bce9e8081604add Mon Sep 17 00:00:00 2001 From: Jonas Neugebauer Date: Sun, 10 Jan 2021 23:51:46 +0100 Subject: [PATCH] Initial commit --- .gitignore | 26 ++++ Edge.java | 75 ++++++++++ Graph.java | 312 ++++++++++++++++++++++++++++++++++++++ List.java | 345 +++++++++++++++++++++++++++++++++++++++++++ Tiefensuche.java | 84 +++++++++++ TiefensucheTest.java | 25 ++++ Vertex.java | 51 +++++++ package.bluej | 59 ++++++++ 8 files changed, 977 insertions(+) create mode 100644 .gitignore create mode 100755 Edge.java create mode 100755 Graph.java create mode 100755 List.java create mode 100644 Tiefensuche.java create mode 100644 TiefensucheTest.java create mode 100755 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/Edge.java b/Edge.java new file mode 100755 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 100755 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 100755 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/Tiefensuche.java b/Tiefensuche.java new file mode 100644 index 0000000..b549a71 --- /dev/null +++ b/Tiefensuche.java @@ -0,0 +1,84 @@ + +/** + * Implementierung der Tiefensuche auf einem ungereichteten, + * gewichteten Graphen. + */ +public class Tiefensuche { + + private Graph g; + + public Tiefensuche() { + g = new Graph(); + + // Aufbau des Graphen + // Erstellen der Knoten (Vertices) + g.addVertex(new Vertex("Köln")); + g.addVertex(new Vertex("Düsseldorf")); + g.addVertex(new Vertex("Dortmund")); + + 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( + g.getVertex("Köln"), + g.getVertex("Dortmund"), + 96.0 + )); + g.addEdge(new Edge( + g.getVertex("Düsseldorf"), + g.getVertex("Dortmund"), + 70.0 + )); + g.addEdge(new Edge(g.getVertex("Dortmund"), bo, 22.0)); + g.addEdge(new Edge(bi, hnv, 113.0)); + Edge bi_do = new Edge(bi, g.getVertex("Dortmund"), 112.0); + g.addEdge(bi_do); + Edge bi_dus = new Edge(bi, g.getVertex("Düsseldorf"), 178.0); + g.addEdge(bi_dus); + Edge bo_dus = new Edge(bo, g.getVertex("Düsseldorf"), 52.0); + } + + /** + * Suche nach einem Vertex mit der angegebenen ID mittels der Tiefensuche. + * @param pVertexID + * @return + */ + public boolean findVertex( String pVertexID ) { + g.setAllVertexMarks(false); // Markierungen zurücksetzen + return findVertex(pVertexID, g.getVertices().getContent()); + } + + /** + * Hilfsmethode für die rekursive Tiefensuche. + * Sucht nach einem Vertex mit der angegebenen ID mittels der Tiefensuche, + * ausgehend vom angegebenen Startknoten. + * @param pVertexID + * @return + */ + private boolean findVertex( String pVertexID, Vertex pCurrent ) { + if( pCurrent.getID().equals(pVertexID) ) { + return true; + } else { + pCurrent.setMark(true); + + List neighbours = g.getNeighbours(pCurrent); + neighbours.toFirst(); + while( neighbours.hasAccess() ) { + Vertex v = neighbours.getContent(); + if( !v.isMarked() ) { + if( findVertex(pVertexID, v) ) { + return true; + } + } + neighbours.next(); + } + } + return false; + } + +} diff --git a/TiefensucheTest.java b/TiefensucheTest.java new file mode 100644 index 0000000..37c4067 --- /dev/null +++ b/TiefensucheTest.java @@ -0,0 +1,25 @@ +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class TiefensucheTest { + + @Before + public void setUp() { + + } + + @Test + public void testFindVertex() { + Tiefensuche ts = new Tiefensuche(); + + 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/Vertex.java b/Vertex.java new file mode 100755 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