forked from IF-LK-2020/tiefensuche
Initial commit
This commit is contained in:
commit
8bce97f653
|
@ -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*
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Klasse Edge
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,312 @@
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Klasse Graph
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||||
|
* @version Oktober 2015
|
||||||
|
*/
|
||||||
|
public class Graph{
|
||||||
|
private List<Vertex> vertices;
|
||||||
|
private List<Edge> 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<Vertex>();
|
||||||
|
edges = new List<Edge>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Anfrage liefert eine neue Liste aller Knotenobjekte vom Typ List<Vertex>.
|
||||||
|
*/
|
||||||
|
public List<Vertex> getVertices(){
|
||||||
|
//Eine neue Liste mit allen Vertex-Objekten erstellen.
|
||||||
|
List<Vertex> result = new List<Vertex>();
|
||||||
|
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<Edge>.
|
||||||
|
*/
|
||||||
|
public List<Edge> getEdges(){
|
||||||
|
//Eine neue Liste mit allen Edge-Objekten erstellen.
|
||||||
|
List<Edge> result = new List<Edge>();
|
||||||
|
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<Vertex>. 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<Vertex> getNeighbours(Vertex pVertex){
|
||||||
|
List<Vertex> result = new List<Vertex>();
|
||||||
|
|
||||||
|
//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<Edge> getEdges(Vertex pVertex){
|
||||||
|
List<Edge> result = new List<Edge>();
|
||||||
|
|
||||||
|
//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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,345 @@
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Generische Klasse List<ContentType>
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Objekt der generischen Klasse List verwalten beliebig viele linear
|
||||||
|
* angeordnete Objekte vom Typ ContentType. Auf hoechstens ein Listenobjekt,
|
||||||
|
* aktuellesObjekt genannt, kann jeweils zugegriffen werden.<br />
|
||||||
|
* Wenn eine Liste leer ist, vollstaendig durchlaufen wurde oder das aktuelle
|
||||||
|
* Objekt am Ende der Liste geloescht wurde, gibt es kein aktuelles Objekt.<br />
|
||||||
|
* 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. <br />
|
||||||
|
* Das aktuelle Objekt kann gelesen, veraendert oder geloescht werden. Ausserdem
|
||||||
|
* kann vor dem aktuellen Objekt ein Listenobjekt eingefuegt werden.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
||||||
|
* @version Generisch_06 2015-10-25
|
||||||
|
*/
|
||||||
|
public class List<ContentType> {
|
||||||
|
|
||||||
|
/* --------- 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. <br />
|
||||||
|
* Wenn die Liste leer ist, wird pContent in die Liste eingefuegt und es
|
||||||
|
* gibt weiterhin kein aktuelles Objekt (hasAccess() == false). <br />
|
||||||
|
* 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.<br />
|
||||||
|
* Ansonsten wird ein neues Objekt pContent am Ende der Liste eingefuegt.
|
||||||
|
* Das aktuelle Objekt bleibt unveraendert. <br />
|
||||||
|
* 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.<br />
|
||||||
|
* 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<ContentType>
|
||||||
|
*/
|
||||||
|
public void concat(List<ContentType> 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.<br />
|
||||||
|
* Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
|
||||||
|
* aktuelle Objekt geloescht und das Objekt hinter dem geloeschten Objekt
|
||||||
|
* wird zum aktuellen Objekt. <br />
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Vertex> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Klasse Vertex
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue