AlgII.FAU.SS03.Kap15_1

Werbung
Gliederung
5. Compiler
1.
2.
3.
4.
Struktur eines Compilers
Syntaxanalyse durch rekursiven Abstieg
Ausnahmebehandlung
Arrays und Strings
6. Sortieren und Suchen
1. Grundlegende Datenstrukturen
2. Bäume
3. Hash-Verfahren (Streuspeicherung)
7. Graphen
1. Darstellung und Topologisches Sortieren
2. Kürzeste Wege
3. Fluß- und Zuordnungsprobleme
Graphen
Ein (gerichteter) Graph ist ein Paar G = <V, E>, wobei gilt:
• V ist eine endliche Menge von Knoten (engl. : Vertex) und
• E ist eine zweistellige Relation auf V, d.h. E ⊆ V x V. Die
Elemente von E werden Kanten (engl. : Edge) genannt.
• Gilt G’ = <V’, E’> mit V’ ⊆ V und E’ ⊆ E,
so heißt G’ Teilgraph von G.
Graphen: Beispiele
(1) V1 = Menge aller Flughäfen in Deutschland.
G1 = { (x,y) ∈ V1 x V1 | Es gibt einen Direktflug zwischen x
und y }
(2) V2 = Bevölkerung von Erlangen
G2 = { (x,y) ∈ V2 x V2 | x kennt y }
(3) V3 = Bevölkerung von Erlangen
G3 = { (x,y) ∈V3 x V3 | x ist verheiratet mit y }.
G3 ist Teilgraph von G2
Bildliche Darstellung von Graphen
Sei G= <V, E>:
• Einen Knoten v ∈ V stellt man durch einen Punkt oder durch
einen kleinen Kreis dar.
• Eine Kante (x,y) ∈ E stellt man durch einen Pfeil vom
Knoten x zum Knoten y dar.
Beispiel:
A
D
V = { A,B,C,D,E,F,G,H }
F
E = { (A,D), (D,A), (A,B),
(B,C), (C,A), (B,E),
(A,E), (F,G), (F,F)}.
B
H
C
G
E
Ungerichtete Graphen
• Sei G = <V,E>.
• Falls für jedes e ∈ E mit e = (v1,v2) gilt: e’ = (v2,v1) ∈ E,
so heißt G ungerichteter Graph, ansonsten gerichteter Graph.
• Die Relation E ist in diesem Fall symmetrisch.
• Bei einem ungerichteten Graphen gehört zu jedem Pfeil von
x nach y auch ein Pfeil von y nach x.
• Daher lässt man Pfeile ganz weg und zeichnet nur
ungerichtete Kanten.
Ungerichtete Graphen: Beispiel
•
•
V = einige Städte
E = { (x,y) |
Es gibt eine direkte Bahnverbindung
zwischen x und y }
4 Kassel
Marburg
Köln 5
Bonn 0
7
Gießen 3
2 Fulda
1 Frankfurt
6
Mannheim
8
Würzburg
Pfade, Zyklen und Gewichte
• Eine Kante k = (x,y) heißt inzident zu x und y.
• Ein Pfad (oder Weg) von x nach y ist eine Folge
(x=a0 , a1, ... , ap=y) von Knoten mit (ai , ai+1 ) ∈ E.
p wird die Länge des Weges von x nach y genannt.
• In einem einfachen Pfad kommt jeder Knoten höchstens
einmal vor.
• Ein Pfad der Länge p > 1 von x nach x, in dem außer x kein
Knoten mehr als einmal vorkommt, heißt Zyklus.
• Ein gerichteter Graph <V, E> heißt zyklenfrei oder
gerichteter azyklischer Graph (engl: directed acyclic graph,
kurz: dag), wenn er keine Zyklen enthält.
Beispiele
(B, C, A, D, A) ist ein Pfad von B
nach A.
A
D
Er enthält einen Zyklus: (A, D, A).
F
(C, A, B, E) ist einfacher Pfad
von C nach E.
B
H
(F, F, F, G) ist ein Pfad.
(A, B, C, A) und (A, D, A) und (F,
F) sind die einzigen Zyklen.
(A, B, E, A) ist kein Pfad und kein
Zyklus.
<{A,B,C,E}, {(A,B), (B,C), (B,E),
(A,E)}> ist ein azyklischer
Teilgraph von G.
G
C
E
Bewertete Graphen
Ein Graph G = <V, E> kann zu einem bewerteten Graphen
G = <V, E, gw(E)> erweitert werden, wenn man eine Gewichtsfunktion
gw: E → int (oder gw: E → float/double)
hinzunimmt, die jeder Kante e ∈ E ein (positives, ganzzahliges oder
reelles) Gewicht gw(e) zuordnet.
Für einen Weg w = (x=a0 , a1, ..., ap=y) heißt
p-1
L(w) = Σ gw(ai, ai+1)
i=0
die bewertete Länge von w.
Im folgenden Beispiel gilt:
L (Marburg, Gießen, Frankfurt, Mannheim) = 184
Bewertete Graphen : Beispiel 1
Köln 5
174
Marburg
Bonn
224
106
3
Gießen
66
181
1
88
6
Mannheim
4 Kassel
96
7
30
34
0
104
2 Fulda
104
Frankfurt
136
93
8 Würzburg
Bewertete Graphen: ein weiteres Beispiel
San Rafael
1
15
Richmond
2
18
San Francisco
15
12
0
3
Oakland
20
15
20
Pacifica 14
5 Hayward
San Mateo
15
Half Moon Bay
Rund um die Bucht
von San Francisco
25
13
20
4
14
18
6
10
10
10
12
20
15
Palo Alto
50
7 Fremont
15
9
8 San Jose
Santa Clara
35
Scotts Valley
Santa Cruz
70
60
Watsonville
11
Ungerichtete Graphen und Zusammenhang
• Ungerichtete Graphen sind Spezialfälle von gerichteten Graphen.
Zusätzlich soll für ungerichtete Graphen gelten: G heißt zusammenhängend, wenn es zwischen je zwei (verschiedenen) Knoten einen Weg
gibt. Ist G nicht zusammenhängend, so zerfällt er in eine Vereinigung
zusammenhängender Komponenten (auch Zusammenhangskomponenten
genannt) .
• Ein zusammenhängender
zyklenfreier Graph ist ein Baum.
F
• Eine Gruppe paarweise nicht
zusammenhängender Bäume
heißt Wald.
• Jeder zyklenfreie ungerichtete
Graph ist also ein Wald.
D
A
B
H
G
C
E
Zusammenhangskomponenten:
Zusammenhangskomponenten:
Beispiel
Beispiel
Zusammenhang in gerichteten Graphen
• Die Definitionen für Zusammenhang und Zusammenhangskomponenten
lassen sich für gerichteten Graphen ausdehnen: Ein gerichteter Graph G
heißt stark zusammenhängend, wenn es zwischen je zwei (verschiedenen)
Knoten einen Weg gibt. Für einen beliebigen Graphen G kann man die
Menge seiner starken Zusammenhangskomponenten betrachten. Zwei
Knoten a und b liegen in der gleichen Komponente Z, wenn sowohl ein
Weg von a nach b als auch einer von b nach a in Z existiert.
• Ein gerichteter Graph G heißt
schwach zusammenhängend,
wenn der entsprechende
ungerichtete Graph, der aus G
durch Hinzunahme aller
Rückwärtskanten entsteht,
zusammenhängend ist.
A
D
F
B
H
G
C
E
Starke
StarkeZusammenhangskomponenten:
Zusammenhangskomponenten:Beispiel
Beispiel
Aufspannender Baum
• Ist G zusammenhängend und R ein zusammenhängender,
zyklenfreier Teilgraph von G, der alle Knoten von G enthält,
so heißt R ein (auf)spannender oder erzeugender Baum
(engl.: spanning tree) von G.
• Einfacher Algorithmus SpT zur Konstruktion des
(auf)spannenden Baums für G:
– Solange es einen Zyklus gibt, entferne eine Kante aus diesem Zyklus
• Rekursiver Algorithmus SpT zur Konstruktion des
(auf)spannenden Baums für G:
– Markiere einen beliebigen Knoten v ∈ V
– Wiederhole für alle von v ausgehenden Kanten e = (v,v') ∈ E:
– Wenn v' unmarkiert, markiere v' und führe SpT (v') aus, sonst lösche
e (und gehe zur nächsten Kante weiter).
Erzeugender Baum : Beispiel
Ein Graph G
Ein erzeugender Baum von G
Repräsentation von Graphen
• Für die Repräsentation eines Graphen kommen in erster Linie zwei
Datenstrukturen in Frage:
– eine Boolesche Matrix (auch Adjazenzmatrix genannt):
– eine Liste oder ein Array von Listen (für die Knoten des Graphen und
deren jeweilige Verbindungen) .
• Repräsentation durch eine Adjazenzmatrix:
• Ein Graph G = ( V, E) ist i.W. durch die Angabe seiner Kanten E ⊆ V x V
bestimmt. So wie Teilmengen von V durch Boolesche Arrays dargestellt
werden können, kann man Teilmengen von V × V durch Boolesche
Matrizen (sog. Adjazenzmatrizen) darstellen.
– boolean [][] Graph;
• Dies setzt natürlich voraus, daß wir mit V eine Aufzählung der Knoten des
Graphen haben.
Adjazenzmatrix: Beispiel
String [] Knoten =
{"A", "B", "C", "D", "E", "F", "G", "H"};
boolean [][] Kanten = {
{false, true, false, true, true, false, false, false},
{false, false, true, false, true, false, false, false},
...
// usw.
};
A
D
F
B
H
C
G
E
A B C D E F G H
A
x
x x
B
x
x
C x
D x
E
F
x x
G
H
( True = x, False = " " )
Definition einer Graph-Klasse (1)
class Graph{
String [] Knoten;
int KnotenZahl;
int[][] Kanten ;
Graph(String [] Knotenliste, int [] [] Kantenliste){
Knoten = Knotenliste;
Kanten = Kantenliste;
KnotenZahl = knoten.length;
}
}
Bewertete Adjazenzmatrizen (1)
• Viele der klassischen Anwendungsbeispiele für Graphen
kommen aus dem Bereich der Verkehrsnetze.
• Wir wollen daher die folgenden Algorithmen anhand zweier
umfangreichen Beispiele aus diesem Bereich erläutern.
• Kanten sind mögliche direkte Verkehrsverbindungen
(Straßen) zwischen Städten.
• Bewertet werden sie mit einer Maßzahl, welche die
Entfernung und/oder den durchschnittlichen Zeitaufwand für
eine Fahrt zwischen den Städten reflektiert.
• Dabei haben die Knoten jeweils einen Namen (den
Städtenamen) und eine Nummer in der Aufzählung.
• Daraus kann man dann eine Matrixdarstellung gewinnen.
Bewertete Adjazenzmatrizen (2)
• Bei dieser Matrix sind die Einträge keine Booleschen Werte
mehr, sondern entsprechen den Bewertungen der Kanten.
• Wenn der Wert nicht in der Matrix erscheint, bedeutet das, daß
keine direkte Verbindung zwischen den entsprechenden Städten
existiert.
• In der Diagonalen steht die Bewertung der Verbindung jeder
Stadt mit sich selbst. Diese wird hier stets mit 0 angenommen.
• Wir haben damit das Prinzip der Adjazenzmatrix auf bewertete
Graphen erweitert.
Statt
Statteines
einesbooleschen
booleschenWerts
Wertsspeichert
speichertman
mandas
das
Gewicht
Gewichtgw
gw(u,v)
(u,v)jeder
jederKante
Kantean
ander
derbetreffenden
betreffenden
Position
PositionM[u,v]
M[u,v]der
derMatrix
MatrixM.
M.
• Ist G ein ungerichteter Graph, so ist die Matrix symmetrisch
- d.h. man kommt im Prinzip mit einer Dreiecksmatrix aus.
Bewertete Adjazenzmatrix: Beispiel 1
0
1
2
3
4
5
6
7
8
0
1
2
3
4
5
6
BN
F
FD
GI
KS
K
MA
MR WÜ
0
181
-
-
-
34
224
-
-
181
0
104
66
-
-
88
-
136
FD
-
104
0
106
96
-
-
-
93
GI
-
66
106
0
-
174
-
30
-
KS
-
-
96
-
0
-
-
104 -
34
-
-
174
-
0
-
-
-
88
-
-
-
-
0
-
-
BN
F
K
MA 224
7
8
MR
-
-
-
30
104
-
-
0
-
WÜ
-
136
93
-
-
-
-
-
0
Bewertete Adjazenzmatrix: Beispiel 2
0
1
2 3 4
5 6 7
8 9 10 11 12 13 14
0
0 18 - 12 20 -
-
-
-
-
-
-
-
- 15
1
18 0 15 -
-
-
-
-
-
-
-
-
-
-
-
- 15 0 15 -
-
-
-
-
-
-
-
-
-
-
3
12 - 15 0 - 20 -
-
-
-
-
-
-
-
-
4
20 -
- 0 20 18 -
-
-
-
-
- 25 -
-
-
-
-
-
-
2
-
5
-
-
- 20 20 0 - 14 -
6
-
-
-
- 18 - 0 15 - 10 -
-
-
-
-
7
-
-
-
-
- 14 15 0 20 -
-
-
-
-
8
-
-
-
-
-
-
- 20 0 15 - 60 -
-
-
9
-
-
-
-
-
- 10 - 15 0 35 -
-
-
10
-
-
-
-
-
-
-
-
- 10 -
-
11
-
-
-
-
-
-
-
- 60 -
0 70 -
-
12
-
-
-
-
-
-
-
-
-
- 10 70 0 50 -
13
-
-
-
- 25 -
-
-
-
-
-
- 50 0 15
15 -
-
-
-
-
-
-
-
-
14
-
-
-
- 35 0
-
-
- 15 0
Adjazenzmatrix für Beispiel 1
• Bildung einer Instanz der Klasse Graph, um den Beispiel-1Graphen zu repräsentieren.
Graph Bsp1 = new Graph(
{"Bonn", "Frankfurt", "Fulda",
"Gießen", "Kassel", "Köln",
"Mannheim", "Marburg", "Würzburg" },
{
});
{
0, 181,
0,
0,
0, 34, 224,
0,
0},
{181,
0, 104, 66,
0,
0, 88,
0, 136},
{ 0, 104,
0, 106, 96,
0,
0,
0, 93},
{ 0, 66, 106,
0,
0, 174,
0, 30,
0},
{ 0,
0, 96,
0,
0,
0,
0, 104,
0},
{ 34,
0,
0, 174,
0,
0,
0,
0,
0},
{224, 88,
0,
0,
0,
0,
0,
0,
0},
{ 0,
0,
0, 30, 104,
0,
0,
0,
0},
{ 0, 136, 93,
0,
0,
0,
0,
0,
0}
Adjazenzmatrix für Beispiel 2
Graph Bsp2 = new Graph(
{ "San Francisco", "San Rafael",
"Richmond", "Oakland", "San Mateo", "Hayward",
"Palo Alto", "Fremont", "San Jose", "Santa Clara",
"Scotts Valley", "Watsonville", "Santa Cruz",
"Half Moon Bay", "Pacifica" },
{
{ 0, 18, 0, 12, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15},
{18, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{12, 0, 15, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{20, 0, 0, 0, 0, 20, 18, 0, 0, 0, 0, 0, 0, 25, 0},
{ 0, 0, 0, 20, 20, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 18, 0, 0, 15, 0, 10, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 14, 15, 0, 20, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 20, 0, 15, 0, 60, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 10, 0, 15, 0, 35, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 10, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 70, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 70, 0, 50, 0},
{ 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 50, 0, 15},
{15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0}
});
Knoten- und Kantenzugriffe
• Der Zugriff auf einzelne Knoten und Kanten ist mit Hilfe
einfacher Zugriffsfunktionen möglich:
String gibKnoten
(int k) {
return Knoten[k];}
int gibKantenW (int u, int v) { return Kanten[u][v];}
Beispiel:
Graph Bsp1 = new Graph();
Bsp1.gibKnoten (3);
Bsp1.gibKantenW (3, 7);
// Ergebnis: "Gießen"
// Ergebnis: 30
Adjazenzlisten (1)
A
Eine alternative, weniger
speicheraufwendige Methode, einen
Graphen darzustellen, besteht
darin, zu jedem Knoten eine Liste
zu definieren, in der die
unmittelbaren Nachbarn samt der
Gewichte ihrer Verbindungen
enthalten sind.
Dabei wird jedem Knoten eine
Adjazenzliste (= Liste seiner
Nachbarknoten) zugeordnet.
D
F
B
H
G
C
E
A
B
C
D
B
C
A
A
D
E
E
E
F
F
G
G
H
Adjazenzlisten (2)
• Die Darstellung eines Graphen mit einer Adjazenzliste spart
Speicherplatz, da die speicheraufwendige (und hochgradig
redundante) Adjazenzmatrix vermieden wird.
• Leider ist bei der Listendarstellung der Aufwand für einen
direkten Zugriff auf den Wert einer Kante von x nach y hoch.
• Dieser Zugriff erfolgt jedoch bei typischen Graphalgorithmen
recht häufig.
• Im Falle der Verwendung einer Adjazenzmatrix ist der Zugriff
direkt möglich, im Falle der Listendarstellung führt der
entsprechende Zugriff zu einer Suche in der Liste aller
Nachbarn.
Adjazenzlisten für Beispiel 1
0
Bonn
1 181
5 34
6 224
null
1
Frankfurt
0 181
2 104
3 66
6 88
8 136
null
2
Fulda
1 104
3 106
4 96
8 93
null
3
Gießen
1 66
2 106
5 174
7 30
null
4
Kassel
2 96
7 104
null
5
Köln
0 34
3 174
null
6
Mannheim
0 224
1 88
null
7
Marburg
3 30
4 104
null
8
Würzburg
1 136
2 93
null
Adjazenzlisten für Beispiel 2
0
San Francisco
18 2
12 4
20 5
15 15
1
San Rafael
18 1
15 3
null
2
Richmond
15 2
15 4
null
3
Oakland
12 1
15 3
20 6
null
4
San Mateo
20 1
20 6
18 7
25 4
5
Hayward
20 4
20 5
14 8
null
6
Palo Alto
18 5
15 8
10 10
null
7
Fremont
14 6
15 7
20 9
null
8
San Jose
20 8
15 10
60 12
null
9
Santa Clara
10 7
15 9
35 11
null
10
Scotts Valley
35 10
10 13
null
11
Watsonville
60 9
70 13
null
12
Santa Cruz
10 10
70 12
50 14
null
13
Half Moon Bay
50 13
25 5
15 15
null
14
Pacifica
15 14
15 1
null
null
Adjazenzliste für Beispiel 2 (1)
• Eine Klasse zur Repräsentation von Verbindungen
class Verbindung{
int Laenge;
int ziel;
Verbindung next;
Verbindung(int l, int w, Verbindung v){
Laenge = l;
ziel = w;
next = v;
}
}
Adjazenzliste für Beispiel 2 (2)
• Eine Klasse zur Repräsentation von Knoten
class KnotenTyp{
String Name;
Verbindung Nachbarn;
KnotenTyp(String s, Verbindung v){
Name = s;
Nachbarn = v;
}
}
Definition einer Graph-Klasse (2)
class Graph{
KnotenTyp [] Knoten;
int KnotenZahl;
Graph(Knotentyp [] KnotenTypListe){
Knoten = KnotenTypListe;
KnotenZahl = knoten.length;
}
}
Adjazenzliste für Beispiel 2 (3)
• Realisierung des Graphen
KnotenTyp [] Knoten = new KnotenTyp[15];
Knoten[ 0] = new KnotenTyp("San Francisco",
new Verbindung(18, 1,
new Verbindung(12, 3,
new Verbindung(20, 4,
new Verbindung(15, 14, null)))));
Knoten[ 1] = new KnotenTyp("San Rafael",
new Verbindung(18, 0,
new Verbindung(15, 2, null)));
Knoten[ 2] = new KnotenTyp("Richmond",
new Verbindung(15, 1,
new Verbindung(15, 3, null)));
.... /// usw. usw. usw....
Graph myGraph= new Graph(Knoten);
Knoten- und Kantenzugriffe
• Der Zugriff auf einzelne Knoten ist immer noch einfach:
String gibKnoten (int k) {
return Knoten[k].Name[k];
}
• Der Zugriff auf einzelne Kanten ist nur mit Hilfe einer
aufwendigeren Zugriffsfunktionen möglich:
int gibKantenW (int u, int v) {
Verbindung vp = Knoten[u].Nachbarn;
while (vp != null){
if (vp.ziel == v) return vp.Laenge;
vp = vp.next;
}
return 0;
}
Implementierung durch Listen von Listen (1)
• Eine weitere Möglichkeit zur Implementierung von
Graphen besteht darin, auch die Folge der Knoten auf
eine Liste abzubilden, d.h. der
B
D E
A
gesamte Graph wird durch
eine Liste von Listen dargestellt.
C
E
B
A
D
F
B
G
E
A
D
A
E
H
C
C
F
G
H
F
G
Implementierung durch Listen von Listen (2)
class Edge {
int dest, cost;
public Edge (int d, int c) {
dest = d;
cost = c;
}
}
public class Graph {
private Hashtable labels;
private Vector nodes;
public Graph () {
labels = new Hashtable ();
nodes = new Vector ();
}
Implementierung durch Listen von Listen (3)
public void addNode (String label) {
if (labels.contains (label))
throw new NodeAlreadyDefinedException ();
nodes.addElement (new LinkedList ());
int idx = nodes.size () - 1;
labels.put (label, new Integer (idx));
}
public int getNodeID (String label) {
Integer i = (Integer) labels.get (label);
if (i == null)
throw new NoSuchElementException ();
return i.intValue ();
}
public void addEdge (String src, String dest, int cost) {
LinkedList adjList = (LinkedList) nodes.elementAt (getNodeID
(src));
adjList.add (new Edge (getNodeID (dest), cost));
}
public Iterator getEdges (int node) {
return ((LinkedList) nodes.elementAt (node)).iterator ();
}
Vergleich der Implementierungen
• Alle hier betrachteten Möglichkeiten zur Implementierung von
Graphen haben ihre spezifischen Vor- und Nachteile.
• Seien n = Knotenzahl und m = Kantenzahl eines Graphen G.
Vorteile
Nachteile
Adjazenzmatrix
Berechnung der
Inzidenz mit O(1)
hoher Platzbedarf und teure
Initialisierung: beide O(n2)
Adjazenzliste
Platzbedarf beträgt
nur O(n+m)
Effizienz der Kantensuche
abhängig von Knotenordnung
O(m)
Liste von
Listen
Knoten lassen sich
flexibel hinzufügen/
löschen
Effizienz von Knoten- und
Kantensuche abhängig von
Listenposition
O(m.n)
Literatur
• Die Vorlesungsfolien wurden aus der Vorlesung „Informatik
II a, SS 2002“ von Prof. Sommer (Uni-Marburg)
übernommen
Herunterladen