Programmieren_Projekt/graph/DirectedGraph.java

331 lines
15 KiB
Java

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<T extends VertexMarking, U extends EdgeMarking> extends Graph<T, U> {
private boolean hasCycle = false;
LogElementList<LogElement> logList = new LogElementList<>(); // Erzeugen einer LogElementList für die Protokollierung
LogElementList<TestLogElement> 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<visualizationElements.Vertex>(), new Vector <visualizationElements.Edge>(), true, EdgeStyle.Direct);
}
public DirectedGraph(String s) {
super(s);
this.visualizedGraph = new visualizationElements.Graph(new Vector<visualizationElements.Vertex>(), new Vector <visualizationElements.Edge>(), 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<visualizationElements.Vertex> 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<visualizationElements.Edge> 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<U> e){
super.addEdge(e);
this.visualizedGraph.getEdges().add(e.getScreenEdge());
}
public void addVertex(MarkedVertex<T> v){
super.addVertex(v);
this.visualizedGraph.getVertexes().add(v.getScreenVertex());
}
public boolean removeEdge(MarkedEdge<U> e){
super.removeEdge(e);
this.visualizedGraph.getEdges().remove(e.getScreenEdge());
return true;
}
public boolean removeVertex(MarkedVertex<T> v){
super.removeVertex(v);
this.visualizedGraph.getVertexes().remove(v.getScreenVertex());
return true;
}
public Vector<visualizationElements.Edge> getEdges() {
return this.visualizedGraph.getEdges();
}
public Vector<visualizationElements.Vertex> getVertexes() {
return this.visualizedGraph.getVertexes();
}
public LogElementList<LogElement> getLogList(){
return this.logList;
}
public LogElementList<TestLogElement> getNewLogList(){
return this.graphLogList;
}
public Vector<MarkedVertex<T>> getPredecessors(MarkedVertex<T> n) {
Vector<MarkedVertex<T>> predecessors = new Vector<>();
for (MarkedEdge<U> edge : getAllEdges()) {
if (edge.getDestination().equals(n)) {
predecessors.add((MarkedVertex<T>) edge.getSource());
}
}
return predecessors;
}
public Vector<MarkedVertex<T>> getSuccessors(MarkedVertex<T> n) {
Vector<MarkedVertex<T>> successors = new Vector<>();
for (MarkedEdge<U> edge : getAllEdges()) {
if (edge.getSource().equals(n)) {
successors.add((MarkedVertex<T>) edge.getDestination());
}
}
return successors;
}
public int inDegree(MarkedVertex<T> n) {
return getPredecessors(n).size();
}
public int inDegree(String s) {
for (MarkedVertex<T> vertex : getAllVertexes()) {
if (vertex.getName().equals(s)) {
return inDegree(vertex);
}
}
return 0;
}
public int outDegree(MarkedVertex<T> n) {
return getSuccessors(n).size();
}
public int outDegree(String s) {
for (MarkedVertex<T> vertex : getAllVertexes()) {
if (vertex.getName().equals(s)) {
return outDegree(vertex);
}
}
return 0;
}
public boolean areStrongAdjacent(MarkedVertex<T> n1, MarkedVertex<T> 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<T> n1, MarkedVertex<T> n2) {
return hasEdge(n1, n2);
}
@Override
public boolean areAdjacent(String s1, String s2) {
return hasEdge(s1, s2);
}
public Vector<MarkedVertex<T>> breadthFirstSearch(MarkedVertex<T> startVertex) {
// Anlegen der Maps, die Farbe udn Distanz speichern
Map<MarkedVertex<T>, String> color = new HashMap<>();
Map<MarkedVertex<T>, Integer> distance = new HashMap<>();
// Vector für die Rückgabe aller gefundenen Knoten
Vector<MarkedVertex<T>> vertices = new Vector<>();
// Schlange von MarkedVertex als LinkedList
Queue<MarkedVertex<T>> queue = new LinkedList<>();
// step für die Protokollierung
step = 0;
this.graphLogList.add(new TestLogElement(0, "0", 0, this.copyVisualizedGraph()));
for (MarkedVertex<T> 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<T> 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<T> 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<MarkedVertex<T>> getNeighbors(MarkedVertex<T> vertex) {
List<MarkedVertex<T>> neighbors = new ArrayList<>();
for (MarkedEdge<U> edge : getAllEdges()) {
if (edge.getSource().equals(vertex)) {
neighbors.add((MarkedVertex<T>) 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<T>) edge.getSource());
}
}
return neighbors;
}
Map<MarkedVertex<T>, Integer> ToSoNr = new HashMap<>();
Map<MarkedVertex<T>, String> Besucht = new HashMap<>();
int nummer = getAllVertexes().size();
public boolean topSort(MarkedVertex<T> 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<T> 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<MarkedVertex<T>, Integer> entry : ToSoNr.entrySet()) {
MarkedVertex<T> vertex = entry.getKey();
Integer num = entry.getValue();
System.out.println("Vertex: " + vertex.getName() + ", Nummer: " + num);
}
logResults();
return hasCycle;
}
public void tsprozedur(MarkedVertex<T> n1){
// Knoten als in Bearbeitung markieren
Besucht.put(n1, "in Bearbeitung");
logList.add(new LogElement(step++, "Wurde besucht - " + n1.getName())); // Logging
for (MarkedVertex<T> 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<T> n1){
return topSort(n1);
}
private void logResults() { // Iteration über logList mit Konsolenausgabe
for (LogElement element : logList) {
System.out.println("Step " + element.getStep() + ": " + element.getDescription());
}
}
}