mirror of
https://codeberg.org/qg-info-unterricht/zpg-graphentester.git
synced 2026-03-25 04:58:24 +01:00
807 lines
27 KiB
Java
807 lines
27 KiB
Java
package graph;
|
|
import imp.*;
|
|
import java.util.List;
|
|
import java.util.ArrayList;
|
|
import java.util.Optional;
|
|
import java.util.function.Predicate;
|
|
import java.util.stream.Collectors;
|
|
|
|
/**
|
|
* Dies ist das Herz vom "GraphTester" - der Graph selber, gepeichert als Adjazenzliste.
|
|
* Die Klasse erlaubt durch geeignete Methoden:
|
|
* - die Speicherung als Adjazenzmatrix,
|
|
* - das Hinzufuegen und Loeschen von knoten und Kanten,
|
|
* - das Markieren von Knoten und Kanten,
|
|
* - eine Aussage darueber, ob Knoten oder Kanten enthalten sind und
|
|
* - eine Ausgabe des Graphen in textueller Form sowie als csv-Datei.
|
|
*
|
|
*
|
|
* @author Dirk Zechnall, Thomas Schaller
|
|
* @version 31.01.2021 (v6.5)
|
|
*/
|
|
|
|
public class Graph
|
|
{
|
|
|
|
private ArrayList<Knoten> kList; // Liste aller Knoten
|
|
private ArrayList<Kante> kaList; // Liste aller Kanten
|
|
private ArrayList<ArrayList<Kante>> adList; //Adjazenzliste
|
|
private boolean gerichtet;
|
|
private boolean gewichtet;
|
|
|
|
/**
|
|
* Der Konstruktor erstellt einen neuen Graphen (genauer eine neue Adjazenzliste)
|
|
* @param isGerichtet gibt an, ob es sich um einen gerichteten Graphen handelt
|
|
* @param isGewichtet gibt an, ob die Kanten gewichtet sind.
|
|
*/
|
|
public Graph (boolean isGerichtet, boolean isGewichtet) {
|
|
loescheGraph();
|
|
gerichtet = isGerichtet;
|
|
gewichtet = isGewichtet;
|
|
}
|
|
|
|
/**
|
|
* Der Konstruktor erstellt einen neuen ungerichteten, ungewichteten Graphen (genauer eine neue Adjazenzliste)
|
|
*/
|
|
public Graph() {
|
|
loescheGraph();
|
|
}
|
|
|
|
/**
|
|
* Löscht alle Knoten und Kanten eines Graphen und stellt auf ungerichtet und ungewichtet zurück.
|
|
*/
|
|
public void loescheGraph() {
|
|
gerichtet = false;
|
|
gewichtet = false;
|
|
kList = new ArrayList<Knoten>();
|
|
kaList = new ArrayList<Kante>();
|
|
adList = new ArrayList<ArrayList<Kante>>();
|
|
}
|
|
|
|
/**
|
|
* Ein Graph wird aus einer csv-Datei erstellt, die entweder
|
|
* eine Matrix oder eine Adjazenzliste enthält, die den Graph beschreibt.
|
|
*
|
|
* @param csvParser Eine CSV-Datei als Table-Objekt
|
|
* @return gibt zurück, ob das Laden erfolgreich war
|
|
*/
|
|
public boolean ladeGraph(Table csvParser) {
|
|
boolean geschafft = false;
|
|
try {
|
|
int knotenAnzahl = 0;
|
|
boolean hasInfotext = false;
|
|
boolean hasStatus = false;
|
|
geschafft = true;
|
|
int start;
|
|
int posx = 0;
|
|
|
|
for(start = 0; start < csvParser.getRowCount(); start++) {
|
|
TableRow row = csvParser.getRow(start);
|
|
String m = row.getString(0);
|
|
if(row.getString(0).equals("directed")) {
|
|
setGerichtet(row.getInt(1) == 1);
|
|
}
|
|
if(row.getString(0).equals("weighted")) {
|
|
setGewichtet(row.getInt(1) == 1);
|
|
}
|
|
if(row.getString(0).equals("matrix") || row.getString(0).equals("list")) {
|
|
String n = row.getString(1);
|
|
if(n.equals("infotext")) {
|
|
hasInfotext = true;
|
|
posx++;
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Knoten erstellen
|
|
for(int i=start+1; i < csvParser.getRowCount(); i++) {
|
|
TableRow row = csvParser.getRow(i);
|
|
if(row.getString(0).isEmpty() || row.getString(0).charAt(0) != '#') {
|
|
Knoten k = new Knoten(row.getInt(posx), row.getInt(posx+1));
|
|
if(hasInfotext) k.setInfotext(row.getString(0));
|
|
|
|
neuerKnoten(k);
|
|
knotenAnzahl++;
|
|
}
|
|
}
|
|
|
|
// Kanten erstellen
|
|
int k=0;
|
|
if(csvParser.getString(start,0).equals("matrix")){
|
|
|
|
for(int i = start+1; i < csvParser.getRowCount(); i++) {
|
|
TableRow row = csvParser.getRow(i);
|
|
if(row.getString(0).isEmpty() || row.getString(0).charAt(0) != '#') { //Ueberpruefung auf Kommentare #
|
|
for(int j = posx+2; j < row.getColumnCount(); j+=1) {
|
|
if(!(row.getString(j).equals("-"))) {
|
|
neueKante(getKnoten(k), getKnoten(j - 2 -posx), row.getDouble(j));
|
|
}
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
for(int i = start+1; i < csvParser.getRowCount(); i++) {
|
|
|
|
TableRow row = csvParser.getRow(i);
|
|
if(row.getString(0).isEmpty() || row.getString(0).charAt(0) != '#') { // Ueberpruefung auf Kommentare #
|
|
int z = row.getColumnCount();
|
|
z++;
|
|
|
|
for(int j = posx+2; j < row.getColumnCount(); j+= 1) {
|
|
if(isGewichtet()){
|
|
neueKante(getKnoten(k), getKnoten(row.getInt(j)), row.getDouble(j + 1));
|
|
j++;
|
|
} else {
|
|
neueKante(getKnoten(k), getKnoten(row.getInt(j)), 0);
|
|
}
|
|
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
}
|
|
|
|
} catch(Exception e) {
|
|
geschafft=false;
|
|
}
|
|
return geschafft;
|
|
}
|
|
|
|
/**
|
|
* Legt fest, ob der Graph gewichtet oder ungewichtet ist.
|
|
*
|
|
* @param isGewichtet neuer Wert
|
|
*/
|
|
public void setGewichtet(boolean isGewichtet) {
|
|
gewichtet = isGewichtet;
|
|
}
|
|
|
|
/**
|
|
* Gibt zurueck, ob der Graph gewichtet oder ungewichtet ist
|
|
*
|
|
* @return gewichtet? (true/false)
|
|
*/
|
|
public boolean isGewichtet() {
|
|
return gewichtet;
|
|
}
|
|
|
|
/**
|
|
* Legt fest, ob der Graph gerichtet oder ungerichtet ist.
|
|
*
|
|
* @param isGerichtet neuer Wert
|
|
*/
|
|
public void setGerichtet(boolean isGerichtet) {
|
|
gerichtet = isGerichtet;
|
|
if(gerichtet) {
|
|
for(Kante k: kaList) {
|
|
adList.get(kList.indexOf(k.getZiel())).remove(k);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Gibt zurueck, ob der Graph gerichtet oder ungerichtet ist.
|
|
*
|
|
* @return gerichtet? (true/false)
|
|
*/
|
|
public boolean isGerichtet() {
|
|
return gerichtet;
|
|
}
|
|
|
|
/** Gibt die Nummer eines Knotens im Graphen zurück
|
|
* @param k gesuchter Knoten
|
|
* @return Nummer des Knotens (mit 0 beginnend)
|
|
*/
|
|
public int getNummer(Knoten k) {
|
|
return kList.indexOf(k);
|
|
}
|
|
|
|
/** Gibt die Nummer einer Kante zurück
|
|
* @param k gesuchte Kante
|
|
* @return Nummer der Kante (mit 0 beginnend)
|
|
*/
|
|
public int getNummer(Kante k) {
|
|
return kaList.indexOf(k);
|
|
}
|
|
|
|
/**
|
|
* Die Methode getAdjazenzMatrix() gibt die Adjazenzmatrix zurueck.
|
|
*
|
|
* @return double[][] Die AdjazenzMatrix als zweidimensionales Array
|
|
*/
|
|
public double[][] getAdjazenzMatrix() {
|
|
double[][] matrix = new double[getAnzahlKnoten()][getAnzahlKnoten()];
|
|
for (int i=0; i<matrix.length; i++){
|
|
for (int j=0; j<matrix[i].length; j++){
|
|
matrix[i][j] = Double.NaN;
|
|
}
|
|
}
|
|
// speichere Liste In Matrix
|
|
for(Kante k : getAlleKanten()) {
|
|
int startKnotenNummer = getNummer(k.getStart());
|
|
int zielKnotenNummer = getNummer(k.getZiel());
|
|
// Wenn keine Kanten existieren, gibt es auch kein Kantengewicht - daher wird hier das Kantengewicht auf NaN ueberprueft
|
|
// man koennte hier auch mit Double-Variablen arbeiten und diese null setzen --> hat jedoch einen deutlich groeßeren Speicheraufwand!
|
|
if(gewichtet) matrix[startKnotenNummer][zielKnotenNummer] = k.getGewicht();
|
|
else matrix[startKnotenNummer][zielKnotenNummer] = 0;
|
|
|
|
}
|
|
return matrix;
|
|
}
|
|
|
|
/**
|
|
* Gibt eine Liste aller Kanten des Graphen zurück.
|
|
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
|
|
* @return Liste aller Kanten
|
|
*/
|
|
public List<Kante> getAlleKanten(Predicate<Kante>... filter) {
|
|
List<Kante> kanten = new ArrayList<Kante>(kaList);
|
|
if(filter.length>0) {
|
|
kanten = kanten.stream() // convert list to stream
|
|
.filter(filter[0])
|
|
.collect(Collectors.toCollection(ArrayList::new));
|
|
}
|
|
return kanten;
|
|
}
|
|
|
|
/**
|
|
* Entfernt die Markierung bei allen Knoten des Graphen.
|
|
*/
|
|
public void entferneMarkierungBeiAllenKnoten() {
|
|
for (Knoten k : kList) {
|
|
k.setMarkiert(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialisiert alle Knoten des Graphen.
|
|
*/
|
|
public void initialisiereAlleKnoten() {
|
|
for (Knoten k : kList) {
|
|
k.init();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialisiert alle Kanten des Graphen.
|
|
*/
|
|
public void initialisiereAlleKanten() {
|
|
for (Kante k: kaList) {
|
|
k.init();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ueberprueft, ob ein Knoten in der Knotenliste enthalten ist.
|
|
* Sobald in der Knotenliste der Knoten k gefunden wird, wird true ausgegeben.
|
|
*
|
|
* @param k Der gesuchte Knoten
|
|
* @return true= ist enthalten, false = ist nicht enthalten
|
|
*/
|
|
public boolean isKnotenEnthalten (Knoten k) {
|
|
return kList.contains(k);
|
|
}
|
|
|
|
/**
|
|
* Gibt die Anzahl der Knoten im Graph zurueck
|
|
*
|
|
* @return Anzahl der Knoten
|
|
*/
|
|
public int getAnzahlKnoten() {
|
|
return kList.size();
|
|
}
|
|
|
|
/**
|
|
* Gibt eine Liste aller Knoten des Graphen zurueck.
|
|
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
|
|
* @return Die Knotenliste. Falls leer wird eine leere Liste zurueckgegeben
|
|
*/
|
|
public List<Knoten> getAlleKnoten(Predicate<Knoten>... filter) {
|
|
List<Knoten> knoten = new ArrayList<Knoten>();
|
|
knoten.addAll(kList);
|
|
if(filter.length>0) {
|
|
knoten = knoten.stream() // convert list to stream
|
|
.filter(filter[0])
|
|
.collect(Collectors.toCollection(ArrayList::new));
|
|
}
|
|
return knoten;
|
|
}
|
|
|
|
/**
|
|
* Gibt die Liste aller Nachbarknoten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
|
|
*
|
|
* @param k Der Knoten, zu dem die Adjazenzliste gesucht wird
|
|
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
|
|
* @return Liste der Nachbarknoten
|
|
*/
|
|
public List<Knoten> getNachbarknoten (Knoten k, Predicate<Knoten>... filter) {
|
|
if(kList.contains(k)) {
|
|
List<Knoten> nachbarn = new ArrayList<Knoten>();
|
|
for (Kante e : adList.get(kList.indexOf(k))) {
|
|
nachbarn.add(e.getAnderesEnde(k));
|
|
} // end of for
|
|
if(filter.length>0) {
|
|
nachbarn = nachbarn.stream() // convert list to stream
|
|
.filter(filter[0])
|
|
.collect(Collectors.toCollection(ArrayList::new));
|
|
}
|
|
return nachbarn;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gibt eine Liste der ausgehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
|
|
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
|
|
* unterschieden.
|
|
*
|
|
* @param k Der Knoten, zu dem die Kanten gesucht werden
|
|
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
|
|
* @return Liste der ausgehenden Kanten.
|
|
*/
|
|
public List<Kante> getAusgehendeKanten (Knoten k, Predicate<Kante>... filter) {
|
|
if(kList.contains(k)) {
|
|
List<Kante> kanten = new ArrayList<Kante>();
|
|
kanten.addAll(adList.get(kList.indexOf(k)));
|
|
if(filter.length>0) {
|
|
kanten = kanten.stream() // convert list to stream
|
|
.filter(filter[0])
|
|
.collect(Collectors.toCollection(ArrayList::new));
|
|
}
|
|
return kanten;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gibt eine Liste der ausgehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
|
|
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
|
|
* unterschieden.
|
|
*
|
|
* @param knotennr Nummer des Knoten, zu dem die Kanten gesucht werden
|
|
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
|
|
* @return Liste der ausgehenden Kanten.
|
|
*/
|
|
public List<Kante> getAusgehendeKanten (int knotennr, Predicate<Kante>... filter) {
|
|
if(knotennr < getAnzahlKnoten()) {
|
|
List<Kante> kanten = new ArrayList<Kante>();
|
|
kanten.addAll(adList.get(knotennr));
|
|
if(filter.length>0) {
|
|
kanten = kanten.stream() // convert list to stream
|
|
.filter(filter[0])
|
|
.collect(Collectors.toCollection(ArrayList::new));
|
|
}
|
|
return kanten;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gibt eine Liste der eingehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
|
|
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
|
|
* unterschieden.
|
|
*
|
|
* @param knotennr Die Nummer des Knotens, zu dem die Kanten gesucht werden
|
|
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
|
|
* @return Liste der eingehenden Kanten.
|
|
*/
|
|
public List<Kante> getEingehendeKanten (int knotennr, Predicate<Kante>... filter) {
|
|
if(knotennr >= getAnzahlKnoten()) {
|
|
return null;
|
|
}
|
|
return getEingehendeKanten(this.getKnoten(knotennr),filter);
|
|
}
|
|
|
|
/**
|
|
* Gibt eine Liste der eingehenden Kanten eines Knotens k zurueck, falls k in der Knotenliste vorhanden ist.
|
|
* Bei ungerichteten Graphen wird nicht zwischen eingehenden und ausgehenden Kanten
|
|
* unterschieden.
|
|
*
|
|
* @param k Knoten, zu dem die Kanten gesucht werden
|
|
* @param filter optionaler Filter, der auf die Liste angewendet wird. Er muss einen boolean-Wert zurückgeben: z.B. @literal{k->k.isMarkiert() && k.isBesucht()}
|
|
* @return Liste der eingehenden Kanten.
|
|
*/
|
|
|
|
public List<Kante> getEingehendeKanten (Knoten k, Predicate<Kante>... filter) {
|
|
if(!kList.contains(k)) {
|
|
return null;
|
|
}
|
|
List<Kante> kanten = new ArrayList<Kante>();
|
|
if(this.isGerichtet()) {
|
|
for (Kante e: kaList) {
|
|
if(e.getZiel()== k) {
|
|
kanten.add(e);
|
|
}
|
|
} // end of for
|
|
} else {
|
|
kanten = getAusgehendeKanten(k);
|
|
} // end of if-else
|
|
|
|
if(filter.length>0) {
|
|
kanten = kanten.stream() // convert list to stream
|
|
.filter(filter[0])
|
|
.collect(Collectors.toCollection(ArrayList::new));
|
|
}
|
|
|
|
return kanten;
|
|
}
|
|
|
|
/**
|
|
* Liefert einen Knoten des Graphen
|
|
* @param knotennr Nummer der Knoten (beginnend mit 0)
|
|
* @return liefert den Knoten mit dieser Nummer
|
|
*/
|
|
public Knoten getKnoten(int knotennr) {
|
|
if(knotennr < getAnzahlKnoten()) {
|
|
return kList.get(knotennr);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fügt einen Knoten dem Graph hinzu.
|
|
* @param k Der Knoten, der hinzugefuegt werden soll
|
|
*/
|
|
public void neuerKnoten (Knoten k) {
|
|
if (!isKnotenEnthalten(k)){
|
|
kList.add(k);
|
|
adList.add(new ArrayList<Kante>());
|
|
k.setGraph(this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Entfernt einen Knoten aus dem Graphen
|
|
*
|
|
* @param knotennr Nummer des Knotens, der geloescht werden soll
|
|
*/
|
|
public void entferneKnoten (int knotennr) {
|
|
entferneKnoten(getKnoten(knotennr));
|
|
}
|
|
|
|
/**
|
|
* Entfernt einen Knoten aus dem Graphen
|
|
*
|
|
* @param k Knoten, der geloescht werden soll
|
|
* @return gibt zurück, ob der Knoten erfolgreich entfernt wurde.
|
|
*/
|
|
|
|
public boolean entferneKnoten (Knoten k) {
|
|
if (!kList.contains(k)) return false;
|
|
|
|
int index = kList.indexOf(k);
|
|
for (List<Kante> a : adList) {
|
|
int index2 = 0;
|
|
while(index2 < a.size()){
|
|
Kante ka = a.get(index2);
|
|
if(ka.getStart()==k || ka.getZiel()==k){
|
|
if(kaList.contains(ka)) kaList.remove(ka);
|
|
a.remove(index2);
|
|
} else {
|
|
index2++;
|
|
}
|
|
}
|
|
}
|
|
adList.remove(index);
|
|
kList.remove(k);
|
|
k.setGraph(null);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Ueberprueft, ob eine Kante im Graphen enthalten ist.
|
|
*
|
|
* @param e Die zu suchende Kante
|
|
* @return Kante enthalten (true) oder nicht (false)
|
|
*/
|
|
public boolean isKanteEnthalten (Kante e) {
|
|
return kaList.contains(e);
|
|
}
|
|
|
|
/**
|
|
* Ueberprueft, ob eine Kante im Graphen enthalten ist.
|
|
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
|
|
*
|
|
* @param startNr Nummer des Startknotens
|
|
* @param zielNr Nummer des Zielknotens
|
|
* @return boolean Kante enthalten (true) oder nicht (false)
|
|
*/
|
|
public boolean isKanteEnthalten (int startNr, int zielNr) {
|
|
return getKante(startNr, zielNr)!=null;
|
|
}
|
|
|
|
/**
|
|
* Ueberprueft, ob eine Kante im Graphen enthalten ist.
|
|
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
|
|
*
|
|
* @param start Startknoten
|
|
* @param ziel Zielknoten
|
|
* @return boolean Kante enthalten (true) oder nicht (false)
|
|
*/
|
|
|
|
public boolean isKanteEnthalten (Knoten start, Knoten ziel) {
|
|
return getKante(start, ziel)!=null;
|
|
}
|
|
|
|
/**
|
|
* Gibt eine gesuchte Kante aus dem Graphen zurueck.
|
|
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
|
|
*
|
|
* @param start Der StartKnoten
|
|
* @param ziel Der StartKnoten
|
|
* @return Die gesuchte Kante
|
|
*/
|
|
public Kante getKante (Knoten start, Knoten ziel) {
|
|
|
|
for(Kante k: adList.get(kList.indexOf(start))) {
|
|
if(k.getStart()==start && k.getZiel() == ziel) {
|
|
return k;
|
|
}
|
|
if(!gerichtet && k.getStart()==ziel && k.getZiel() == start) {
|
|
return k;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gibt eine gesuchte Kante aus dem Graphen zurueck.
|
|
* In ungerichteten Graphen wird nicht zwischen Start- und Zielknoten unterschieden
|
|
*
|
|
* @param startnr Der Nummer des StartKnoten
|
|
* @param zielnr Die Nummer des Zielknoten
|
|
* @return Die gesuchte Kante
|
|
*/
|
|
public Kante getKante (int startnr, int zielnr) {
|
|
return getKante(getKnoten(startnr), getKnoten(zielnr));
|
|
}
|
|
|
|
/**
|
|
* Fuegt eine Kante dem Graphen hinzu.
|
|
* Dabei wird ueberprueft, ob die Kante schon im Graphen enthalten ist.
|
|
*
|
|
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" erstellt.
|
|
*
|
|
* @param e Die Kante, die hinzugefuegt werden soll
|
|
*/
|
|
public void neueKante(Kante e) {
|
|
adList.get(kList.indexOf(e.getStart())).add(e);
|
|
if(!gerichtet) adList.get(kList.indexOf(e.getZiel())).add(e);
|
|
kaList.add(e);
|
|
e.setGraph(this);
|
|
}
|
|
|
|
/**
|
|
* Fuegt eine Kante dem Graphen hinzu.
|
|
* Dabei wird ueberprueft, ob die Kante schon im Graphen enthalten ist.
|
|
*
|
|
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" erstellt.
|
|
*
|
|
* @param start Der StartKnoten der Kante, die hinzugefuegt werden soll
|
|
* @param ziel Der ZielKnoten der Kante, die hinzugefuegt werden soll
|
|
* @param gewicht Das Gewicht der Kante, die hinzugefuegt werden soll
|
|
*/
|
|
public void neueKante(Knoten start, Knoten ziel, double gewicht) {
|
|
if(!kList.contains(start) || !kList.contains(ziel) || getKante(start,ziel) != null) return;
|
|
neueKante(new Kante(start,ziel, gewicht));
|
|
}
|
|
|
|
/**
|
|
* Entfernt eine Kante aus dem Graphen.
|
|
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" entfernt.
|
|
*
|
|
* @param e Die zu entfernende Kante
|
|
*/
|
|
public void entferneKante (Kante e) {
|
|
entferneKante(e.getStart(), e.getZiel());
|
|
|
|
}
|
|
|
|
/**
|
|
* Entfernt eine Kante aus dem Graphen.
|
|
* Dabei wird ueberprueft, ob die Kante ueberhaupt im Graphen enthalten ist.
|
|
*
|
|
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" entfernt.
|
|
*
|
|
* @param start StartKnotens
|
|
* @param ziel ZielKnotens
|
|
*/
|
|
public void entferneKante (Knoten start, Knoten ziel) {
|
|
Kante e1 = getKante(start, ziel);
|
|
Kante e2 = getKante(ziel, start);
|
|
|
|
for(List<Kante> a: adList) {
|
|
a.remove(e1);
|
|
if(!gerichtet) {
|
|
a.remove(e2);
|
|
}
|
|
}
|
|
kaList.remove(e1);
|
|
e1.setGraph(null);
|
|
if(!gerichtet) {
|
|
kaList.remove(e2);
|
|
e2.setGraph(null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Entfernt eine Kante aus dem Graphen.
|
|
* Ist der Graph ungerichtet, werden sowohl "Hin-" und "RueckKante" entfernt.
|
|
*
|
|
* @param startnr Nummer des StartKnotens
|
|
* @param zielnr Nummer des ZielKnotens
|
|
*/
|
|
public void entferneKante (int startnr, int zielnr) {
|
|
entferneKante(getKnoten(startnr), getKnoten(zielnr));
|
|
}
|
|
|
|
/**
|
|
* Ueberprueft, ob die Adjazenzliste leer ist, d.h. keine Knoten im Graphen enthalten sind.
|
|
*
|
|
* @return true, wenn die Liste leer ist, sonst false
|
|
*/
|
|
public boolean isLeer() {
|
|
return adList.isEmpty();
|
|
}
|
|
|
|
/**
|
|
* Loescht den gesamten Graphen
|
|
*/
|
|
public void loescheAlles() {
|
|
for(Kante k : kaList) k.setGraph(null);
|
|
for(Knoten k : kList) k.setGraph(null);
|
|
adList.clear();
|
|
kList.clear();
|
|
kaList.clear();
|
|
}
|
|
|
|
/**
|
|
* Die Methode erstellt eine CSV-Ausgabe des Graphen entweder als Adjazenzliste oder als Adjazenzmatrix.
|
|
*
|
|
* @param asMatrix true, falls die CSV-Ausgabe eine AdjazenzMatrix sein soll, sonst false
|
|
* @return CSV-Ausgabe
|
|
*/
|
|
|
|
public String toCSVString(boolean asMatrix) {
|
|
String s="";
|
|
//if(adList.isLeer()) return s;
|
|
s += "# gewichtet 1, ungewichtet 0\n";
|
|
s += "weighted,"+(isGewichtet() ? "1" : "0")+"\n";
|
|
s += "# gerichtet 1, ungerichtet 0\n";
|
|
s += "directed,"+(isGerichtet() ? "1" : "0")+"\n";
|
|
|
|
// Kontrollieren, ob irgendwo ein Infotext vorhanden ist.
|
|
boolean hasInfotext = false;
|
|
for(Knoten k: kList) {
|
|
if(!k.getInfotext().equals("")) hasInfotext = true;
|
|
}
|
|
|
|
if(asMatrix){
|
|
s += "# Der Graph liegt hier in Form einer Adjazenzmatrix vor. \n";
|
|
s += "# Jede Zeile steht fuer einen Knoten, durch Kommas getrennt stehen die Kantengewicht zu jedem anderen Knoten.\n";
|
|
|
|
s += "matrix";
|
|
if(hasInfotext) s+=",infotext";
|
|
double[][] matrix = getAdjazenzMatrix();
|
|
// hier muss ueberprueft werden, ob matrixinhalt ist NaN --> '-' speichern
|
|
for (int i=0; i<matrix.length; i++){
|
|
s+="\n";
|
|
Knoten k = kList.get(i);
|
|
if(hasInfotext) s+=k.getInfotext()+",";
|
|
s+=(k.getX())+","+k.getY()+",";
|
|
for (int j=0; j<matrix[i].length; j++){
|
|
if(Double.isNaN(matrix[i][j]))s+="-";
|
|
else s+=matrix[i][j];
|
|
if (j!=matrix.length-1) s+=",";
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
s += "# Der Graph liegt hier in Form einer Adjazenzliste vor.\n";
|
|
s += "# Jede Zeile steht fuer einen Knoten, durch Komma getrennt steht der adjazente Knoten mit dem zugehoerigen Kantengewicht.\n";
|
|
s += "list";
|
|
if(hasInfotext) s+=",infotext";
|
|
|
|
for(int knr = 0; knr < kList.size(); knr++) {
|
|
s+="\n";
|
|
Knoten k = kList.get(knr);
|
|
List<Kante> a = adList.get(knr);
|
|
if(hasInfotext) s+=k.getInfotext()+",";
|
|
s+=(k.getX())+","+(k.getY());
|
|
if (a.size()>0) s+=",";
|
|
for (Kante ka : a) {
|
|
s+=""+(getNummer(ka.getAnderesEnde(k)));
|
|
if (isGewichtet()) s+=","+ka.getGewicht();
|
|
if (a.get(a.size()-1)!=ka) s+=",";
|
|
}
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Textuelle Repraesentation des Graphen.
|
|
*
|
|
* @return Der Graph als Stringrepraesentation
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
String s="";
|
|
s+="Adjazenzliste:\n";
|
|
if(adList.isEmpty()) return "Liste ist leer!\n";
|
|
for(int i=0; i< kList.size(); i++) {
|
|
s+="K"+i+kList.get(i).toString()+": ";
|
|
List<Kante> a =adList.get(i);
|
|
for (Kante k : a) {
|
|
s+=k.toString()+"K"+(kList.indexOf(k.getAnderesEnde(kList.get(i))))+" | ";
|
|
}
|
|
s=s.substring(0,s.length()-3)+"\n";
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Konsolenausgabe der textuellen Repraesentation des Graphen.
|
|
*/
|
|
public void ausgabe() {
|
|
System.out.println(toString());
|
|
}
|
|
|
|
/**
|
|
* Info über einen Knoten zurückgeben
|
|
* @param k Knoten, des Info ermittelt werden soll
|
|
* @param zeigeWert Soll der Wert des Knoten in der Info enthalten sein
|
|
* @return Infotext oder Nummer des Knoten und ggf. sein Wert
|
|
*/
|
|
public String getKnoteninfo(Knoten k, boolean zeigeWert) {
|
|
String info = "";
|
|
if (!k.getInfotext().equals("")) {
|
|
info += k.getInfotext();
|
|
} else {
|
|
info += "Knoten Nr. "+getNummer(k);
|
|
}
|
|
if( zeigeWert) {
|
|
info += " (Wert "+k.getDoubleWert()+")";
|
|
}
|
|
return info;
|
|
}
|
|
|
|
/** Speichert den Zustand des Graphen als String-List
|
|
* @return List mit Zustand
|
|
*/
|
|
public List<String> getStatus() {
|
|
List<String> status = new ArrayList<String>();
|
|
for(Knoten k : getAlleKnoten()) {
|
|
status.add(k.getStatus());
|
|
}
|
|
for(Kante k : getAlleKanten()) {
|
|
status.add(k.getStatus());
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/** Stellt den Zustand des Graphen aus String-List wieder her
|
|
* @param status List mit Zustand
|
|
*/
|
|
public void setStatus(List<String> status) {
|
|
int i=0;
|
|
for(Knoten k : getAlleKnoten()) {
|
|
k.setStatus(status.get(i++));
|
|
}
|
|
for(Kante k : getAlleKanten()) {
|
|
k.setStatus(status.get(i++));
|
|
}
|
|
|
|
}
|
|
}
|