8 Java: Datenstrukturen für Graphen

Werbung
8 Java: Datenstrukturen für Graphen
8.1 Datenstrukturen für Graphen
8.2 Graphen als dynamische Datenstruktur
8
8.3 Graphen als Kantenliste
8.4 Graphen als Knotenliste
8.5 Graphen als Adjazenzmatrix
8.6 Graphen als Adjazenzlisten
109
8 Java: Datenstrukturen für Graphen
Teil VIII
Java: Datenstrukturen für Graphen
Überblick
Datenstrukturen für Graphen
Graphen als dynamische Datenstruktur
Graphen als Kantenliste
Graphen als Knotenliste
Graphen als Adjazenzmatrix
Graphen als Adjazenzlisten
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–1
Datenstrukturen für Graphen
◮
Verschiedene mögliche Implementierungsalternativen
◮
Auswahl je nach Anwendung und Aufwand für Operationen
◮
◮
Hier: Grundprinzipien für verschiedene Alternativen
vorgestellt
Eingeschränkte Implementierungen
◮
◮
◮
Gerichteter, ungewichteter Graph
Durchgehend durchnummerierte Knoten
Nur Erzeugen von Knoten und Kanten, kein Löschen
Saake/Schallehn
110
Algorithmen & Datenstrukturen II
8–2
Uni Magdeburg, WS 2005/06
8 Java: Datenstrukturen für Graphen
Allgemeine Schnittstelle für
Beispielimplementierung
◮
◮
Schnittstelle in Graph.java
Implementiert als dynamische Datenstruktur, Knotenliste,
Kantenliste, Adjazenzliste und Adjazenzmatrix
public interface Graph {
8
public int addNode();
public boolean addEdge(int orig, int dest);
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–3
Testrahmen
◮
Testrahmen in GraphTest.java
...
Graph elg = new EdgeListGraph();
for (int i = 1; i <= 4; i++)
elg.addNode();
for (int i = 0; i < 10; i++) {
int orig = 1 + (int) (4 * Math.random());
int dest = 1 + (int) (4 * Math.random());
elg.addEdge(orig,dest);
} ...
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–4
Graphen als dynamische Datenstruktur
◮
◮
Vergleichsweise aufwändige Implementierung und
komplexe Operationen
Grundidee entsprechend Bäumen
◮
◮
◮
◮
◮
◮
Graph besteht aus Objekten einer speziellen Knotenklasse
Kanten umgesetzt durch Java-Referenzen
EntryPoints als Knoten ohne eingehende Kanten
(entspricht etwa Baumwurzel)
EntryPoints erlauben Zugriff auf alle Graphenknoten durch
direkte oder indirekte Erreichbarkeit
Gewichtete Graphen würden Kantenklasse erfordern
Ungerichtete Graphen würden bidirektionale Referenzen
erfordern (entsprechend doppelter Verkettung)
Saake/Schallehn
Algorithmen & Datenstrukturen II
Uni Magdeburg, WS 2005/06
8–5
111
8 Java: Datenstrukturen für Graphen
Dynamisch: Klassenstruktur
public class DynamicGraph implements Graph {
public class GraphNode
implements Comparable<GraphNode> {
int key;
Set<GraphNode> edges = null;
GraphNode(int k) {
key = k;
edges = new TreeSet<GraphNode>();
}
...
}
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–6
Dynamisch: Klassenstruktur
public class DynamicGraph implements Graph {
...
Set<GraphNode> entryPoints = null;
int maxKey = 0;
DynamicGraph() {
entryPoints = new TreeSet<GraphNode>();
}
...
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–7
Dynamisch: Knoten hinzufügen
◮
◮
◮
Einfaches Erzeugen eines neuen Knotens als EntryPoint
Gewährleistung der Erreichbarkeit, da bisher keine Kante
zu diesem Knoten möglich
Durchnumerierung der Knoten
public int addNode() {
entryPoints.add(new GraphNode(++maxKey));
return maxKey;
}
Saake/Schallehn
112
Algorithmen & Datenstrukturen II
8–8
Uni Magdeburg, WS 2005/06
8 Java: Datenstrukturen für Graphen
Dynamisch: Knoten Suchen
◮
Kanten Hinzufügen erfordert Finden von Knoten
Einfacher Suchalgorithmus
◮
◮
◮
◮
◮
Kompletter Durchlauf des Graphen
Todo: Merken der noch zu besuchenden Knoten in Menge,
entspricht anfangs EntryPoints
Done: Merken der schon besuchten Knoten in weiterer
Menge zur Vermeidung von Zyklen
Beim Besuchen jeden Knotens hinzufügen der Knoten
ausgehender Kanten zu Todo-Menge, wenn diese noch
nicht in Done-Menge sind
Abbruch wenn Knoten gefunden oder alle Knoten
durchsucht
Saake/Schallehn
Algorithmen & Datenstrukturen II
8
◮
8–9
Dynamisch: Knoten Suchen /2
GraphNode findNode(int k) {
TreeSet<GraphNode> todoSearch =
new TreeSet<GraphNode>();
todoSearch.addAll(entryPoints);
Set<GraphNode> searchDone =
new TreeSet<GraphNode>();
while(!todoSearch.isEmpty()) {
GraphNode n = todoSearch.first();
if (n.key == k) return n;
todoSearch.remove(n); searchDone.add(n);
for (GraphNode e : n.edges)
if (!searchDone.contains(e))
todoSearch.add(e);
}
return null;
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–10
Dynamisch: Kante Hinzufügen
1. Finden von Ausgangs- und Zielknoten
2. Setzen der Kantenbeziehung
3. Da Zielknoten nun indirekt erreichbar ist, kann er aus den
EntryPoints entfernt werden
4. Mögliches Problem: durch einen Zyklus ist nun der
Ausgangsknoten nicht mehr erreichbar
◮
◮
Einaches Beispiel: Einfügen der Kante 1 → 1
Ist der Ausgangsknoten dadurch nicht mehr erreichbar,
wird er wieder zu den EntryPoints hinzugefügt
Saake/Schallehn
Algorithmen & Datenstrukturen II
Uni Magdeburg, WS 2005/06
8–11
113
8 Java: Datenstrukturen für Graphen
Dynamisch: Kante Hinzufügen /2
public boolean addEdge(int orig, int dest) {
GraphNode origNode = findNode(orig);
GraphNode destNode = findNode(dest);
if (origNode == null || destNode == null)
return false;
origNode.edges.add(destNode);
entryPoints.remove(destNode);
if (findNode(orig) == null)
entryPoints.add(origNode);
return true;
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–12
Graphen als Kantenliste
◮
◮
◮
Erstes Element: Anzahl der Knoten
Zweites Element: Anzahl der Kanten
Alle weiteren Wertepaare: Kanten-Codierungen
1
2
3
4
5
6
6, 11, 1, 2, 1, 3, 3, 1, 4, 1, 3, 4, 3, 6, 5, 3, 5, 5, 6, 5, 6, 2, 6, 4
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–13
Graphen als Kantenliste /2
◮
Array-basiert Implementierung
Knoten hinzufügen:
◮
Kante hinzufügen:
◮
◮
◮
◮
◮
◮
Hochsetzen des Knotenzählers
Zwei Einträge an Ende des Arrays anhängen
Hochsetzen des Kantenzählers
Problemfall 1: Knoten existieren nicht
Problemfall 2: Kante existiert bereits
Saake/Schallehn
114
Algorithmen & Datenstrukturen II
8–14
Uni Magdeburg, WS 2005/06
8 Java: Datenstrukturen für Graphen
Kantenliste: Knoten Hinzufügen
public class EdgeListGraph implements Graph {
private int[] edgeList = {0,0};
public int addNode() {
return ++edgeList[0];
}
...
8
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–15
Kantenliste: Kante Hinzufügen /1
public boolean addEdge(int orig, int dest) {
if (orig > edgeList[0] || dest > edgeList[0]
|| orig < 1 || dest < 1)
return false;
for (int i = 2; i < edgeList.length; i += 2)
if (edgeList[i] == orig
&& edgeList[i+1] == dest)
return false;
...
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–16
Kantenliste: Kante Hinzufügen /2
...
int[] newEdgeList = new int[edgeList.length+2];
System.arraycopy(edgeList,0,
newEdgeList,0,edgeList.length);
newEdgeList[newEdgeList.length-2]=orig;
newEdgeList[newEdgeList.length-1]=dest;
edgeList = newEdgeList;
newEdgeList[1]++;
return true;
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
Uni Magdeburg, WS 2005/06
8–17
115
8 Java: Datenstrukturen für Graphen
Graphen als Knotenliste
◮
◮
◮
Erstes Element: Anzahl der Knoten
Zweites Element: Anzahl der Kanten
Danach für jeden Knoten: Codierung der Anzahl
ausgehender Kanten n und der n Zielknoten
1
2
3
4
5
6
6, 11, 2, 2, 3, 0, 3, 1, 4, 6, 1, 1, 2, 3, 5, 3, 2, 4, 5
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–18
Graphen als Knotenliste /2
◮
◮
Array-basiert Implementierung
Knoten hinzufügen:
◮
◮
◮
Hochsetzen des Knotenzählers
Anhängen einer 0 als Knotengrad des neuen Knotens an
Array
Kante hinzufügen:
◮
◮
◮
◮
◮
◮
Position des Knotens im Array finden
Zielknoten in Array einfügen
Hochsetzen des Knotengrads
Hochsetzen des Kantenzählers
Problemfall 1: Knoten existieren nicht
Problemfall 2: Kante existiert bereits
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–19
Knotenliste: Knoten Einfügen
public class NodeListGraph implements Graph {
private int[] nodeList = {0,0};
public int addNode() {
int[] newNodeList =
new int[nodeList.length+1];
System.arraycopy(nodeList,0,
newNodeList,0,nodeList.length);
newNodeList[newNodeList.length-1]=0;
nodeList = newNodeList;
nodeList[0]++;
return nodeList[0];
}
...
}
Saake/Schallehn
116
Algorithmen & Datenstrukturen II
8–20
Uni Magdeburg, WS 2005/06
8 Java: Datenstrukturen für Graphen
Knotenliste: Kante Einfügen /1
Saake/Schallehn
Algorithmen & Datenstrukturen II
8
public boolean addEdge(int orig, int dest) {
if (orig > nodeList[0] || dest > nodeList[0]
|| orig < 1 || dest < 1)
return false;
int pos = 2;
for (int i = 1; i < orig; i++)
pos += 1 + nodeList[pos];
for (int i = 1; i <= nodeList[pos]; i++)
if (nodeList[pos+i] == dest)
return false;
...
8–21
Knotenliste: Kante Einfügen /2
...
int[] newNodeList = new int[nodeList.length+1];
System.arraycopy(nodeList,0,newNodeList,0,pos+1);
System.arraycopy(nodeList,pos+1,
newNodeList,pos+2,nodeList.length-pos-1);
newNodeList[pos]++;
newNodeList[pos+1]=dest;
newNodeList[1]++;
nodeList = newNodeList;
return true;
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–22
Graphen als Adjazenzmatrix




Gg = 



0
0
1
1
0
0
1
0
0
0
0
1
1
0
0
0
1
0
0
0
1
0
0
1
0
0
0
0
1
1
0
0
1
0
0
0








1
2
Saake/Schallehn
3
4
5
6
Algorithmen & Datenstrukturen II
Uni Magdeburg, WS 2005/06
8–23
117
8 Java: Datenstrukturen für Graphen
Graphen als Adjazenzmatrix /2
◮
◮
Zweidimensionales Array von boolean
Knoten hinzufügen:
◮
◮
Vergrößern der Adjazenzmatrix um jeweils eine zusätzliche
leere Spalte und Zeile
Kante hinzufügen:
◮
Setzen eines Bits in der Adjazenzmatrix
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–24
Adjazenzmatrix: Datenstruktur
public class AdjacencyMatrixGraph implements Graph {
private boolean[][] adjacencyMatrix = null;
...
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–25
Adjazenzmatrix: Knoten hinzufügen
public int addNode() {
int nodeNumber = (adjacencyMatrix == null) ?
0 : adjacencyMatrix.length;
boolean[][] newAdjacencyMatrix =
new boolean[nodeNumber+1][nodeNumber+1];
for (int i = 0; i < nodeNumber+1; i++)
for (int j = 0; j < nodeNumber+1; j++)
if (i == nodeNumber || j == nodeNumber)
newAdjacencyMatrix[i][j]=false;
else
newAdjacencyMatrix[i][j]=
adjacencyMatrix[i][j];
adjacencyMatrix = newAdjacencyMatrix;
return nodeNumber+1;
}
Saake/Schallehn
118
Algorithmen & Datenstrukturen II
8–26
Uni Magdeburg, WS 2005/06
8 Java: Datenstrukturen für Graphen
Adjazenzmatrix: Kante Hinzufügen
Saake/Schallehn
Algorithmen & Datenstrukturen II
8
public boolean addEdge(int orig, int dest) {
int nodeNumber = (adjacencyMatrix == null) ?
0 : adjacencyMatrix.length;
if (orig > nodeNumber || dest > nodeNumber
|| orig < 1 || dest < 1)
return false;
if (adjacencyMatrix[orig-1][dest-1])
return false;
adjacencyMatrix[orig-1][dest-1] = true;
return true;
}
8–27
Graphen als Adjazenzlisten
1
2
3
3
1
4
4
1
5
3
5
6
2
4
2
Saake/Schallehn
6
5
Algorithmen & Datenstrukturen II
8–28
Graphen als Adjazenzlisten /2
◮
Dynamik umsetzbar als Liste von Listen
◮
Hier Array (Knoten) von Arrays (adjazente Knoten)
→ ebenfalls zweidimensionales Array
Knoten hinzufügen:
◮
Kante hinzufügen:
◮
◮
◮
Knoten-Array wächst um eine Position
Array für adjazente Knoten wächst um einen Eintrag
Saake/Schallehn
Algorithmen & Datenstrukturen II
Uni Magdeburg, WS 2005/06
8–29
119
8 Java: Datenstrukturen für Graphen
Adjazenzliste: Datenstruktur
public class AdjacencyListGraph implements Graph {
private int[][] adjacencyList = null;
...
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–30
Adjazenzliste: Knoten Hinzufügen
public int addNode() {
int nodeNumber = (adjacencyList == null) ?
0 : adjacencyList.length;
int[][] newAdjacencyList =
new int[nodeNumber+1][];
for (int i = 0; i < nodeNumber; i++)
newAdjacencyList[i]=adjacencyList[i];
newAdjacencyList[nodeNumber] = null;
adjacencyList = newAdjacencyList;
return nodeNumber+1;
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
8–31
Adjazenzliste: Kante Hinzufügen /1
public boolean addEdge(int orig, int dest) {
int nodeNumber = (adjacencyList == null) ?
0 : adjacencyList.length;
if (orig > nodeNumber || dest > nodeNumber
|| orig < 1 || dest < 1)
return false;
if (adjacencyList[orig-1] != null)
for (int n : adjacencyList[orig-1])
if (n == dest) return false;
if (adjacencyList[orig-1] == null) {
adjacencyList[orig-1] = new int[1];
adjacencyList[orig-1][0] = dest;
}
...
Saake/Schallehn
120
Algorithmen & Datenstrukturen II
8–32
Uni Magdeburg, WS 2005/06
8 Java: Datenstrukturen für Graphen
Adjazenzliste: Kante Hinzufügen /1
8
...
else {
int[] newList =
new int[adjacencyList[orig-1].length+1];
System.arraycopy(adjacencyList[orig-1],0,
newList,0,adjacencyList[orig-1].length);
newList[adjacencyList[orig-1].length] = dest;
adjacencyList[orig-1] = newList;
}
return true;
}
Saake/Schallehn
Algorithmen & Datenstrukturen II
Uni Magdeburg, WS 2005/06
8–33
121
Herunterladen