commit d70ce4a163ef7246280411165fb51bd1c0bba590 Author: Jonathan-Kalmbach Date: Wed Jul 10 05:24:10 2024 +0000 Dateien nach "graph" hochladen diff --git a/graph/Anwendung.java b/graph/Anwendung.java new file mode 100644 index 0000000..21e6e96 --- /dev/null +++ b/graph/Anwendung.java @@ -0,0 +1,71 @@ +package graph; + +import static java.awt.Color.black; + +public class Anwendung { + public static void main(String[] args) { + // Erstellen eines gerichteten Graphen + DirectedGraph graph = new DirectedGraph<>(); + + // Erstellen und Hinzufügen von Knoten + MarkedVertex vertexA = new MarkedVertex<>("A", new VertexMarking() { + }, 10, 10, black); + MarkedVertex vertexB = new MarkedVertex<>("B", new VertexMarking() { + }, 10, 100, black); + MarkedVertex vertexC = new MarkedVertex<>("C", new VertexMarking() { + }, 100, 10, black); + MarkedVertex vertexD = new MarkedVertex<>("D", new VertexMarking() { + }, 600, 100, black); + MarkedVertex vertexE = new MarkedVertex<>("E", new VertexMarking() { + }, 100, 60, black); + MarkedVertex vertexF = new MarkedVertex<>("F", new VertexMarking() { + }, 160, 100, black); + MarkedVertex vertexG = new MarkedVertex<>("G", new VertexMarking() { + }, 100, 160, black); + + + graph.addVertex(vertexA); + graph.addVertex(vertexB); + graph.addVertex(vertexC); + graph.addVertex(vertexD); + graph.addVertex(vertexE); + graph.addVertex(vertexF); + graph.addVertex(vertexG); + + // Erstellen und Hinzufügen von Kanten + graph.addEdge(new MarkedEdge<>("Edge1", vertexA, vertexB, new EdgeMarking() { + })); + graph.addEdge(new MarkedEdge<>("Edge2", vertexB, vertexC, new EdgeMarking() { + })); + graph.addEdge(new MarkedEdge<>("Edge3", vertexC, vertexD, new EdgeMarking() { + })); + + graph.addEdge(new MarkedEdge<>("Edge7", vertexC, vertexE, new EdgeMarking() { + })); + + graph.addEdge(new MarkedEdge<>("Edge4", vertexD, vertexE, new EdgeMarking() { + })); + + graph.addEdge(new MarkedEdge<>("Edge8", vertexD, vertexG, new EdgeMarking() { + })); + graph.addEdge(new MarkedEdge<>("Edge5", vertexE, vertexF, new EdgeMarking() { + })); + + graph.addEdge(new MarkedEdge<>("Edge6", vertexF, vertexG, new EdgeMarking() { + })); + + //System.out.println(graph.areStrongAdjacent("A", "B")); + //System.out.println(graph.numberOfEdges()); + System.out.println("Vorgänger von A"); + System.out.println(graph.getPredecessors(vertexA)); + System.out.println("Vorgänger von D"); + System.out.println(graph.getPredecessors(vertexD)); + System.out.println("Vorgänger von D"); + System.out.println(graph.getSuccessors(vertexC)); + + + System.out.println(graph.topSort(vertexA)); + System.out.println(""); + + } +} diff --git a/graph/DirectedGraph.java b/graph/DirectedGraph.java new file mode 100644 index 0000000..be2eabd --- /dev/null +++ b/graph/DirectedGraph.java @@ -0,0 +1,330 @@ +package graph; + +import java.awt.*; +import java.util.*; +import java.util.List; +import java.util.Queue; + +import logging.GraphLogElement; +import logging.LogElement; +import logging.LogElementList; +import logging.NewLogElement; +import testApplication.TestLogElement; +import visualizationElements.EdgeStyle; + +import javax.swing.*; + +public class DirectedGraph extends Graph { + + private boolean hasCycle = false; + + LogElementList logList = new LogElementList<>(); // Erzeugen einer LogElementList für die Protokollierung + LogElementList graphLogList = new LogElementList<>(); // Erzeugen einer LogElementListe von TestLogElementen, in der der Zustand des Graphen protokolliert wird + private visualizationElements.Graph visualizedGraph; + int step = 0; + + + + + public DirectedGraph() { + super(); + this.visualizedGraph = new visualizationElements.Graph(new Vector(), new Vector (), true, EdgeStyle.Direct); + } + + public DirectedGraph(String s) { + super(s); + this.visualizedGraph = new visualizationElements.Graph(new Vector(), new Vector (), true, EdgeStyle.Direct); + } + + public visualizationElements.Graph getVisualizedGraph() { + return this.visualizedGraph; + } + + public visualizationElements.Graph copyVisualizedGraph() { + // Neue Instanz des Graphen erstellen + visualizationElements.Graph snapshotOfVisualizedGraph = new visualizationElements.Graph(new Vector<>(), new Vector<>(), true, EdgeStyle.Direct); + + // Kopiere alle Vertexes + Vector snapshotOfVertexes = new Vector<>(); + // Iteration über alle Vertexe + for (visualizationElements.Vertex vertex : this.visualizedGraph.getVertexes()) { + + // Dem Vector der Vertexe alle Vertexe des visualizedGraph hinzufügen, wobei die Methoden für x,y,Marking und Farbe abgerufen werden + snapshotOfVertexes.add(new visualizationElements.Vertex(vertex.getXpos(), vertex.getYpos(), vertex.getMarking(), vertex.getColor())); + } + snapshotOfVisualizedGraph.setVertexes(snapshotOfVertexes); // Setze die kopierten Vertexes im neuen Graphen + + // Kopiere alle Edges + Vector snapshotOfEdges = new Vector<>(); + for (visualizationElements.Edge edge : this.visualizedGraph.getEdges()) { + + // Dem Vector der Edges alle Edges des visualizedGraph hinzufügen, auch hier wieder Methodenabruf für Source,Destination, Marking und Farbe + snapshotOfEdges.add(new visualizationElements.Edge(edge.getSource(), edge.getDestination(), edge.getMarking(), edge.getColor())); + } + snapshotOfVisualizedGraph.setEdges(snapshotOfEdges); // Setze die kopierten Edges im neuen Graphen + + return snapshotOfVisualizedGraph; + } + public void addEdge(MarkedEdge e){ + super.addEdge(e); + this.visualizedGraph.getEdges().add(e.getScreenEdge()); + } + public void addVertex(MarkedVertex v){ + super.addVertex(v); + this.visualizedGraph.getVertexes().add(v.getScreenVertex()); + } + public boolean removeEdge(MarkedEdge e){ + super.removeEdge(e); + this.visualizedGraph.getEdges().remove(e.getScreenEdge()); + return true; + } + public boolean removeVertex(MarkedVertex v){ + super.removeVertex(v); + this.visualizedGraph.getVertexes().remove(v.getScreenVertex()); + return true; + } + public Vector getEdges() { + return this.visualizedGraph.getEdges(); + } + + public Vector getVertexes() { + return this.visualizedGraph.getVertexes(); + } + + public LogElementList getLogList(){ + return this.logList; + } + + public LogElementList getNewLogList(){ + return this.graphLogList; + } + + public Vector> getPredecessors(MarkedVertex n) { + Vector> predecessors = new Vector<>(); + for (MarkedEdge edge : getAllEdges()) { + if (edge.getDestination().equals(n)) { + predecessors.add((MarkedVertex) edge.getSource()); + } + } + return predecessors; + } + + public Vector> getSuccessors(MarkedVertex n) { + Vector> successors = new Vector<>(); + for (MarkedEdge edge : getAllEdges()) { + if (edge.getSource().equals(n)) { + successors.add((MarkedVertex) edge.getDestination()); + } + } + return successors; + } + + public int inDegree(MarkedVertex n) { + return getPredecessors(n).size(); + } + + public int inDegree(String s) { + for (MarkedVertex vertex : getAllVertexes()) { + if (vertex.getName().equals(s)) { + return inDegree(vertex); + } + } + return 0; + } + + public int outDegree(MarkedVertex n) { + return getSuccessors(n).size(); + } + + public int outDegree(String s) { + for (MarkedVertex vertex : getAllVertexes()) { + if (vertex.getName().equals(s)) { + return outDegree(vertex); + } + } + return 0; + } + + public boolean areStrongAdjacent(MarkedVertex n1, MarkedVertex n2) { + // Implement the logic for strong adjacency in directed graphs + return (hasEdge(n1, n2) && hasEdge(n2, n1)); + } + + public boolean areStrongAdjacent(String s1, String s2) { + // Implement the logic for strong adjacency using names + return (hasEdge(s1, s2)&&hasEdge(s2, s1)); + } + @Override + public boolean areAdjacent(MarkedVertex n1, MarkedVertex n2) { + return hasEdge(n1, n2); + } + + @Override + public boolean areAdjacent(String s1, String s2) { + return hasEdge(s1, s2); + } + + + public Vector> breadthFirstSearch(MarkedVertex startVertex) { + // Anlegen der Maps, die Farbe udn Distanz speichern + Map, String> color = new HashMap<>(); + Map, Integer> distance = new HashMap<>(); + // Vector für die Rückgabe aller gefundenen Knoten + Vector> vertices = new Vector<>(); + // Schlange von MarkedVertex als LinkedList + Queue> queue = new LinkedList<>(); + // step für die Protokollierung + step = 0; + + this.graphLogList.add(new TestLogElement(0, "0", 0, this.copyVisualizedGraph())); + + for (MarkedVertex v : getAllVertexes()) { + color.put(v, "weiß"); // Alle Knoten zunächst weiß + distance.put(v, Integer.MAX_VALUE); // Unendliche Distanz + + v.getScreenVertex().setColor(Color.white); // Setzen der Farbe weiß, des ScreenVertex + // Protokollierung für Konsolenausgabe & Visualisierung + logList.add(new LogElement(step++, "Farbe weiß gesetzt für: " + v.getName() + ", Distanz auf unendlich gesetzt.")); + this.graphLogList.add(new TestLogElement(1, "0", 0,this.copyVisualizedGraph())); + } + + // Startknoten initialisieren und als Grau markieren + color.put(startVertex, "grau"); // in Map + startVertex.getScreenVertex().setColor(Color.gray); // als ScreenVertex + this.graphLogList.add(new TestLogElement(2, "0", 0,this.copyVisualizedGraph())); + + // startVertex in Distanzmap, in Queue und in gefundene Vertexe + distance.put(startVertex, 0); + queue.add(startVertex); + vertices.add(startVertex); + + logList.add(new LogElement(step++, "Startknoten " + startVertex.getName() + " auf grau gesetzt, Distanz = 0.")); + + while (!queue.isEmpty()) { + MarkedVertex current = queue.poll(); // Oberstes Element der Schlange als momentanten Knoten setzen + logList.add(new LogElement(step++, "Dequeue Knoten: " + current.getName())); // Protokollierung + + + // Prozessieren aller Nachbarn des aktuellen Knotens + for (MarkedVertex neighbor : getNeighbors(current)) { + if (color.get(neighbor).equals("weiß")) { // Wenn der Nachbar noch nicht besucht wurde + color.put(neighbor, "grau"); + neighbor.getScreenVertex().setColor(Color.gray); + + // alle Nachbarn des aktuellen Knoten werden in die Maps und in die Queue aufgenommen + distance.put(neighbor, distance.get(current) + 1); + queue.add(neighbor); + vertices.add(neighbor); + + // Protokollierung + logList.add(new LogElement(step++, "Nachbar " + neighbor.getName() + " auf grau gesetzt, Distanz erhöht zu " + distance.get(neighbor))); + this.graphLogList.add(new TestLogElement(3, "0", 0,this.copyVisualizedGraph())); + + } + } + current.getScreenVertex().setColor(Color.black); + + color.put(current, "schwarz"); // Markieren des aktuellen Knotens als vollständig verarbeitet + queue.remove(current); + logList.add(new LogElement(step++, "Knoten " + current.getName() + " auf schwarz gesetzt.")); + this.graphLogList.add(new TestLogElement(4, "0", 0,this.copyVisualizedGraph())); + } + logResults(); + return vertices; + } + + private List> getNeighbors(MarkedVertex vertex) { + List> neighbors = new ArrayList<>(); + for (MarkedEdge edge : getAllEdges()) { + if (edge.getSource().equals(vertex)) { + neighbors.add((MarkedVertex) edge.getDestination()); + } + // Breitensuche in beide Richtungen, da auch Nachbarn, die auf den Knoten zeigen, als Nachbarn erkannt werden (kann verändert werden, indem man einfach das else if ausklammert) + else if (edge.getDestination().equals(vertex)){ + neighbors.add((MarkedVertex) edge.getSource()); + } + } + return neighbors; + } + + + Map, Integer> ToSoNr = new HashMap<>(); + Map, String> Besucht = new HashMap<>(); + int nummer = getAllVertexes().size(); + + public boolean topSort(MarkedVertex n1){ + // Zurücksetzen der verwendeten Maps + Besucht.clear(); + ToSoNr.clear(); + step = 0; // Step als 0 deklarieren als Protokollierungsvariable + n1.getScreenVertex().setColor(Color.white); // Startknoten n1 als weiß setzen, für bessere Übersichtlichkeit bei Visualisierung + this.graphLogList.add(new TestLogElement(0, "0", 0,this.copyVisualizedGraph())); // Übergabe aktueller Graph an graphLogList + + for (MarkedVertex vertex : getAllVertexes()){ // Für jeden Vertex überprüfe, ob er schon in Besucht vorhanden ist + if (!Besucht.containsKey(vertex)){ // Bei Reihenfolge von Eingabe A,B,C erst den A nehmen, und dann Rekursion bis C + logList.add(new LogElement(step++, "Nicht besucht: " + vertex.getName())); + tsprozedur(vertex); // Übergabe von unbesuchtem Knoten an tsprozedur + } + } + // Wenn die Knoten alle abgearbeitet wurden ohne Zyklus: + if (!hasCycle) { + logList.add(new LogElement(step++, "Topologische Sortierung erfolgreich.")); + } + // Ausgabe der ToSoNr Map auf der Konsole + for (Map.Entry, Integer> entry : ToSoNr.entrySet()) { + MarkedVertex vertex = entry.getKey(); + Integer num = entry.getValue(); + System.out.println("Vertex: " + vertex.getName() + ", Nummer: " + num); + } + logResults(); + return hasCycle; + } + + + public void tsprozedur(MarkedVertex n1){ + // Knoten als in Bearbeitung markieren + Besucht.put(n1, "in Bearbeitung"); + logList.add(new LogElement(step++, "Wurde besucht - " + n1.getName())); // Logging + + for (MarkedVertex vertex : getSuccessors(n1)) { + // Zyklus gefunden, wenn der Nachfolger bereits in Bearbeitung ist + // Wenn Nachfolger in Besucht existiert und "in Bearbeitung" markiert ist und es nicht der direkte Vorgänger ist (Doppelkante) + + if (Besucht.get(vertex) != null && Besucht.get(vertex).equals("in Bearbeitung") && !getPredecessors(n1).contains(vertex)) { + logList.add(new LogElement(step++, "Zyklus gefunden bei Knoten " + vertex.getName() + " von " + n1.getName())); + vertex.getScreenVertex().setColor(Color.red); + n1.getScreenVertex().setColor(Color.red); + this.graphLogList.add(new TestLogElement(2, "0", 0,this.copyVisualizedGraph())); // In graphLogList wird eine aktuelle Instanz des Graphen gespeichert + hasCycle = true; + return; + } + // Falls Nachfolger noch nicht besucht wurde -> Eine Rekursion tiefer mit Nachfolger + else if (!Besucht.containsKey(vertex)) { + tsprozedur(vertex); + if (hasCycle) return; // Stoppe weitere Verarbeitung, wenn Zyklus gefunden + } + } + // Markiere Knoten als vollständig besucht + // Wenn es keinen Nachfolger mehr zum rekursiven Aufruf gibt + Besucht.put(n1, "besucht"); // Setze Knoten n1 in Besucht-Map auf "besucht" + ToSoNr.put(n1, (nummer--)+getAllVertexes().size()); //Setze Knoten n1 in TopSortNummer-Map auf Anzahl aller Knoten - nummer(bei letztem Knoten -1) + logList.add(new LogElement(step++, "Knoten " + n1.getName() + " als vollständig besucht markiert. Topologische Nummer:" + ToSoNr.get(n1))); // Protokollierung für Konsolenausgabe + + + n1.getScreenVertex().setMarking(String.valueOf(ToSoNr.get(n1))); // Setze die Bezeichnung der Knoten als Nummer für die Visualisierung + this.graphLogList.add(new TestLogElement(1, "0", 0,this.copyVisualizedGraph())); // In graphLogList wird eine aktuelle Instanz des Graphen gespeichert + + } + + public boolean hasCycle(MarkedVertex n1){ + return topSort(n1); + } + + private void logResults() { // Iteration über logList mit Konsolenausgabe + for (LogElement element : logList) { + System.out.println("Step " + element.getStep() + ": " + element.getDescription()); + } + } + + +} diff --git a/graph/Edge.java b/graph/Edge.java new file mode 100644 index 0000000..2b27a4d --- /dev/null +++ b/graph/Edge.java @@ -0,0 +1,39 @@ +package graph; + +public abstract class Edge { + private String name; + private Vertex source; + private Vertex destination; + + public Edge() {} + + public Edge(String s, Vertex n1, Vertex n2) { + this.name = s; + this.source = n1; + this.destination = n2; + } + + public Vertex getDestination() { + return destination; + } + + public String getName() { + return name; + } + + public Vertex getSource() { + return source; + } + + public void setDestination(Vertex n) { + this.destination = n; + } + + public void setName(String s) { + this.name = s; + } + + public void setSource(Vertex n) { + this.source = n; + } +} \ No newline at end of file diff --git a/graph/EdgeMarking.java b/graph/EdgeMarking.java new file mode 100644 index 0000000..7aa0c81 --- /dev/null +++ b/graph/EdgeMarking.java @@ -0,0 +1,4 @@ +package graph; + +public abstract class EdgeMarking extends Marking{ +} diff --git a/graph/Graph.java b/graph/Graph.java new file mode 100644 index 0000000..16a66e7 --- /dev/null +++ b/graph/Graph.java @@ -0,0 +1,197 @@ +package graph; + +import logging.LogElement; +import logging.LogElementList; + +import java.util.Vector; +public abstract class Graph { + private String name; + private Vector> vertexes = new Vector<>(); + private Vector> edges = new Vector<>(); + + public Graph() {} + + public Graph(String s) { + this.name = s; + } + + public void addEdge(MarkedEdge e) { + edges.add(e); + } + + public void addVertex(MarkedVertex n) { + vertexes.add(n); + } + + public boolean areAdjacent(MarkedVertex n1, MarkedVertex n2){ + for (MarkedEdge edge: edges){ + if (edge.getSource() == n1 && edge.getDestination() == n2 || edge.getDestination() == n1 && edge.getSource() == n2){ + return true; + } + } + return false; + } + + public boolean areAdjacent(String s1, String s2){ + for (MarkedEdge edge: edges){ + if (edge.getSource().getName().equals(s1) && edge.getDestination().getName().equals(s2)){ + return true; + } + else if (edge.getSource().getName().equals(s2) && edge.getDestination().getName().equals(s1)){ + return true; + } + } + return false; + } + + public int degree() { + return edges.size(); + } + + public Vector> getAllEdges() { + return this.edges; + } + + public Vector> getAllVertexes() { + return this.vertexes; + } + + public String getName() { + return this.name; + } + + public abstract visualizationElements.Graph getVisualizedGraph(); + public abstract LogElementList getLogList(); + + /* + public Vector getNeighbors(Vertex n1){ + Vector neighbors = new Vector<>(); + + for (MarkedEdge edge : edges) { + if (edge.getSource().equals(n1)) { + + neighbors.add(edge.getDestination()); + } + else if (edge.getDestination().equals(n1)){ + neighbors.add(edge.getSource()); + } + } + return neighbors; + } + */ + + public boolean hasEdge(MarkedEdge e) { + return edges.contains(e); + } + + public boolean hasEdge(String s) { + for (MarkedEdge edge : edges) { + if (edge.getName().equals(s)) { + return true; + } + } + return false; + } + + public boolean hasEdge(MarkedVertex v1, MarkedVertex v2) { + for (MarkedEdge edge : edges) { + if (edge.getSource().equals(v1) && edge.getDestination().equals(v2)) { + return true; + } + else if (edge.getSource().equals(v2) && edge.getDestination().equals(v1)) { + return true; + } + } + return false; + } + + public boolean hasEdge(String s1, String s2) { + for (MarkedEdge edge : edges) { + if (edge.getSource().getName().equals(s1) && edge.getDestination().getName().equals(s2)) { + return true; + } + else if (edge.getSource().getName().equals(s2) && edge.getDestination().getName().equals(s1)) { + return true; + } + } + return false; + } + + public boolean hasLoop(MarkedVertex n) { + for (MarkedEdge edge : edges) { + if (edge.getSource().equals(n) && edge.getDestination().equals(n)) { + return true; + } + } + return false; + } + + public boolean hasLoop(String s) { + for (MarkedEdge edge : edges) { + if (edge.getSource().getName().equals(s) && edge.getDestination().getName().equals(s)) { + return true; + } + } + return false; + } + + public Boolean hasVertex(MarkedVertex n) { + return vertexes.contains(n); + } + + public boolean hasVertex(String s) { + for (MarkedVertex vertex : vertexes) { + if (vertex.getName().equals(s)) { + return true; + } + } + return false; + } + + public int numberOfEdges() { + return edges.size(); + } + + public int numberOfVertexes() { + return vertexes.size(); + } + + public boolean removeEdge(MarkedEdge e) { + return edges.remove(e); + } + + public boolean removeEdge(String s) { + for (MarkedEdge edge : edges) { + if (edge.getName().equals(s)) { + return edges.remove(edge); + } + } + return false; + } + + public boolean removeVertex(MarkedVertex n) { + return vertexes.remove(n); + } + + public boolean removeVertex(String s) { + for (MarkedVertex vertex : vertexes) { + if (vertex.getName().equals(s)) { + return vertexes.remove(vertex); + } + } + return false; + } + + public void setName(String n) { + this.name = n; + } + + @Override + public String toString() { + return "Graph{" + "name='" + name + '\'' + ", vertexes=" + vertexes + ", edges=" + edges + '}'; + } +} + + + +