Informatik · Klasse 9–13 · aktualisiert
Graphenalgorithmus: Graphen modellieren und lösen
Du lernst, was Knoten und Kanten sind, wie man Graphen speichert und wofür Breitensuche, Tiefensuche, Dijkstra und Kruskal gut sind.
0 von 12 Aufgaben gelöst
Kurz gesagt
Ein Graph besteht aus Knoten und Kanten. Man speichert ihn als Adjazenzliste oder Adjazenzmatrix. Breiten- und Tiefensuche besuchen die Knoten in einer festgelegten Reihenfolge. Dijkstra sucht kürzeste Pfade, Kruskal einen minimalen Spannbaum.
Auf einem U-Bahn-Plan suchst du den Weg zu einer Station. Der Plan ist ein Netz aus Punkten und Verbindungen, also ein Graph. Mit ein paar klaren Regeln kann ein Computer in so einem Netz suchen. Genau diese Regeln lernst du hier.
Deine Lernziele
Hake ab, was du schon kannst. Löst du alle Aufgaben eines Abschnitts, hakt Mela das Ziel für dich ab.
4 Abschnitte
Ein Graph ist eine abstrakte Struktur. Er besteht aus Objekten und den Verbindungen zwischen ihnen. Die Objekte heißen Knoten (auch Ecken). Die paarweisen Verbindungen heißen Kanten (manchmal auch Bögen). Man zeichnet Knoten meist als Punkte und Kanten als Linien.
Ein U-Bahn-Netz ist ein gutes Beispiel: Jeder Knoten stellt eine U-Bahn-Station dar und jede Kante eine direkte Zugverbindung zwischen zwei Stationen. Auch andere Dinge lassen sich so beschreiben. In der chemischen Graphentheorie sind die Atome eines Moleküls die Knoten und die Molekularverbindungen die Kanten. Das Internet ist ein riesiger Graph aus Computern und Datenverbindungen.
Kanten können gerichtet oder ungerichtet sein. Bei einem ungerichteten Graphen haben die Kanten keine Richtung: Jede Kante kann in beide Richtungen durchlaufen werden. Bei einem gerichteten Graphen (auch Digraph genannt) zeichnet man Pfeile, die vom Anfangsknoten zum Endknoten zeigen. Jede Kante kann dann nur in eine Richtung durchlaufen werden. Zwei Knoten heißen benachbart, wenn eine Kante sie verbindet.
Manchmal reicht es nicht zu wissen, welche Knoten verbunden sind. Dann bekommen die Kanten ein Gewicht. In einem Straßennetz könnte das Gewicht zum Beispiel die Entfernung zwischen zwei Orten sein.
Definition
Graph
Ein Graph ist eine abstrakte Struktur aus Objekten (Knoten) und den Verbindungen zwischen ihnen (Kanten). Die Kanten können gerichtet oder ungerichtet sein.
| Merkmal | Ungerichteter Graph | Gerichteter Graph |
|---|---|---|
| Zeichnung der Kante | Linie | Pfeil |
| Durchlaufen | in beide Richtungen | nur in eine Richtung |
Merke: Die Knoten sind die Objekte, die Kanten sind die Verbindungen. Ungerichtete Kanten gehen in beide Richtungen, gerichtete nur in Pfeilrichtung.
Teste dich
Im Computer gibt es im Wesentlichen zwei gebräuchliche Formen, einen Graphen zu speichern: die Adjazenzliste und die Adjazenzmatrix. Praktisch jede algorithmische Lösung für Graphenprobleme greift auf mindestens eine der beiden zurück.
Bei der Adjazenzliste gibst du für jeden Knoten eine Liste an. In einem ungerichteten Graphen stehen darin alle seine Nachbarn, in einem gerichteten Graphen alle seine Nachfolger. Die Reihenfolge der Knoten in der Liste ist beliebig. Im einfachsten Fall speichert man in einem Array für jeden Knoten eine einfach verkettete Liste aller Nachbarn.
Die Adjazenzmatrix ist eine Tabelle mit einer Zeile und einer Spalte für jeden Knoten. Bei n Knoten ist sie eine n × n-Matrix. Der Eintrag in Zeile i und Spalte j sagt, ob eine Kante vom i-ten zum j-ten Knoten führt. Eine 0 bedeutet: keine Kante. Eine 1 bedeutet: Es gibt eine Kante. Bei einem ungerichteten Graphen ist (i, j) genau dann eine Kante, wenn auch (j, i) eine ist. Darum ist seine Matrix immer symmetrisch.
Beide Formen haben Vor- und Nachteile. Die Matrix ist leicht umzusetzen, und man sieht direkt am Eintrag, ob zwei Knoten verbunden sind. Dafür braucht sie Speicher für n × n Einträge. Deshalb wird sie für Graphen in der Praxis selten genutzt.
Definition
Adjazenzliste
Eine Adjazenzliste gehört zu einem Knoten. Sie führt alle seine Nachbarn auf, bei einem gerichteten Graphen alle seine Nachfolger. Die Adjazenzliste des ganzen Graphen besteht aus den Listen aller Knoten.
Beispiel: Gerichteter Graph mit fünf Knoten
- 1Knoten a, b, c, d, e. Kanten: (a,b), (a,d), (a,e), (b,c), (c,d), (d,a).
- 2Adjazenzliste: a: b, d, e · b: c · c: d · d: a · e: (leer, e hat keinen Nachfolger)
- 3Adjazenzmatrix, Zeilen und Spalten in der Reihenfolge a b c d e (aus der Regel abgeleitet):
- 4a: 0 1 0 1 1 · b: 0 0 1 0 0 · c: 0 0 0 1 0 · d: 1 0 0 0 0 · e: 0 0 0 0 0
- 5Die Matrix ist nicht symmetrisch, weil der Graph gerichtet ist: (a,b) gibt es, (b,a) nicht.
| Aufgabe | Adjazenzliste | Adjazenzmatrix |
|---|---|---|
| Alle Nachbarn eines Knotens finden | Die Liste des Knotens lesen | Eine ganze Zeile lesen |
| Kante zwischen zwei Knoten prüfen | In den Listen nachsehen | Direkt am Eintrag ablesen |
Teste dich
Breitensuche und Tiefensuche besuchen die Knoten eines Graphen der Reihe nach. Damit das Ergebnis eindeutig ist, legt man vorher fest, in welcher Reihenfolge die Nachbarn eines Knotens drankommen. Zum Beispiel nimmt man die Reihenfolge der Adjazenzliste. Auch der Startknoten und die Frage, ob der Graph gerichtet ist, können die Reihenfolge ändern.
Breitensuche: Du wählst einen Startknoten, markierst ihn als gesehen und legst ihn in eine Warteschlange. Dann wiederholst du: Nimm den vordersten Knoten aus der Warteschlange. Hänge alle seine noch nicht markierten Nachfolger hinten an und markiere sie als gesehen. Ist die Warteschlange leer, ist die Suche zu Ende. So werden zuerst alle Knoten besucht, die vom Start direkt erreichbar sind, und erst danach die Folgeknoten, Ebene für Ebene.
Tiefensuche: Du besuchst den Startknoten. Dann gehst du zum ersten noch nicht besuchten Nachbarn und machst dort dasselbe, also rekursiv. So folgst du einem Pfad immer weiter in die Tiefe. Hat ein Knoten keinen unbesuchten Nachbarn mehr, gehst du Schritt für Schritt zurück und probierst beim vorigen Knoten den nächsten Nachbarn.
Der Unterschied liegt in der Datenstruktur: Die Breitensuche merkt sich die Knoten in einer Warteschlange, die Tiefensuche in einer anderen Datenstruktur, einem Stapelspeicher.
Beispiel: Kleiner Graph, Start bei A (von einem Rechner berechnet, kein Zitat)
- 1Ungerichteter Graph, Nachbarn in dieser Reihenfolge: A:B,C B:A,D,E C:A,F D:B E:B,F F:C,E
- 2Breitensuche: A raus, neu B, C (Warteschlange: B C). B raus, neu D, E (C D E). C raus, neu F (D E F). D, E und F bringen nichts Neues.
- 3Besuchsreihenfolge Breitensuche: A B C D E F
- 4Tiefensuche: A, dann B, dann D. D hat nichts Neues, also zurück zu B und weiter zu E, dann F, dann C.
- 5Besuchsreihenfolge Tiefensuche: A B D E F C
Merke: Die Breitensuche arbeitet mit einer Warteschlange und besucht Ebene für Ebene. Die Tiefensuche folgt einem Pfad bis zum Ende und geht erst dann zurück.
Teste dich
Die Breitensuche kann man für viele Fragen in Graphen nutzen. Sie findet zum Beispiel zwischen zwei Knoten einen kürzesten Pfad, wenn die Kanten kein Gewicht haben. Jede durch Breitensuche gefundene Lösung hat den kürzesten Abstand zum Startknoten, gemessen in Kanten. Haben die Kanten Gewichte, muss die Lösung, die am nächsten am Start liegt, nicht unbedingt die mit den geringsten Kosten sein. Sind alle Kantengewichte gleich, ist sie dagegen optimal.
Der Algorithmus von Dijkstra löst das Problem der kürzesten Pfade für einen gegebenen Startknoten. In einem kantengewichteten Graphen berechnet er einen kürzesten Pfad vom Start zu einem oder zu allen anderen Knoten, sofern der Graph keine Negativkanten enthält. Negative Kantengewichte können zu nicht optimalen Lösungen führen. Die Grundidee: Er folgt immer der Kante, die den kürzesten Streckenabschnitt vom Start aus verspricht. Ein typisches Beispiel ist der Routenplaner. Der Graph ist dort das Verkehrswegenetz, und gesucht ist die kürzeste Route zwischen zwei Punkten.
Der Algorithmus von Kruskal berechnet minimale Spannbäume von ungerichteten Graphen. Der Graph muss dazu zusammenhängend, kantengewichtet und endlich sein. Kruskal sortiert zuerst die Kanten aufsteigend nach ihrem Gewicht. Dann geht er sie der Reihe nach durch. Eine Kante kommt dazu, wenn sie zwei Knoten verbindet, die noch nicht durch einen Pfad der vorher gewählten Kanten verbunden sind. Ein Netzbetreiber, der Städte verbinden und dabei möglichst wenig Geld für Kabel ausgeben will, nutzt solche Berechnungen.
Der Spannbaum, den Dijkstra am Ende liefert, ist nicht notwendigerweise minimal. Für einen minimalen Spannbaum nimmt man zum Beispiel den Algorithmus von Kruskal.
Definition
Minimaler Spannbaum
Ein Spannbaum ist ein Teilgraph eines ungerichteten Graphen. Er ist ein Baum, also zusammenhängend und ohne geschlossene Pfade, und enthält alle Knoten des Graphen. Er ist minimal, wenn kein anderer Spannbaum desselben Graphen ein geringeres Gewicht hat. Das Gewicht ist die Summe der Kantengewichte.
| Verfahren | Wofür | Graph |
|---|---|---|
| Breitensuche | Einen kürzesten Pfad zwischen zwei Knoten finden | Kanten ohne Gewicht |
| Dijkstra | Kürzeste Pfade ab einem Startknoten berechnen | Kantengewichte, keine negativen |
| Kruskal | Einen minimalen Spannbaum berechnen | ungerichtet, zusammenhängend, kantengewichtet |
Merke: Kürzeste Wege ohne Gewichte: Breitensuche. Kürzeste Wege mit Gewichten, ohne negative Kanten: Dijkstra. Günstigstes Netz, das alle Knoten verbindet: Kruskal.
Teste dich
Alles auf einen Blick
Graphenalgorithmus
Graph
Knoten sind die Objekte, Kanten die Verbindungen, gerichtet oder ungerichtet
Speichern
Adjazenzliste (Nachbarn je Knoten) oder Adjazenzmatrix (n × n mit 0 und 1)
Breitensuche
Warteschlange, Ebene für Ebene, Nachbarn in festgelegter Reihenfolge
Tiefensuche
einem Pfad in die Tiefe folgen, dann Schritt für Schritt zurückgehen
Einsatz
Dijkstra für kürzeste Pfade, Kruskal für minimale Spannbäume
Musteraufgabe · Schritt für Schritt
Breitensuche und Tiefensuche ab H (ausgedachtes Beispiel)
- 1Ungerichteter Graph, Nachbarn in dieser Reihenfolge: H:I,J I:H,L J:H,L,M L:I,J M:J. Start bei H.
- 2Breitensuche: H raus, neu I, J. Warteschlange: I J
- 3I raus, neu L (H ist schon gesehen). Warteschlange: J L
- 4J raus, neu M (H und L sind schon gesehen). Warteschlange: L M
- 5L raus und M raus: nichts Neues. Besuchsreihenfolge: H I J L M
- 6Tiefensuche: H, dann I (erster Nachbar von H), dann L (I hat außer H nur L), dann J (L hat außer I nur J), dann M
- 7M hat nichts Neues. Zurück bis H: alle Nachbarn sind besucht. Besuchsreihenfolge: H I L J M
Fehler finden
Prüfe die Schritte der Breitensuche ab P (ausgedachtes Beispiel) In einer Zeile steckt ein Fehler. Tippe sie an.
Fehler in Zeile 4S wurde schon bei Q entdeckt und ist markiert, darum wird S nicht noch einmal angehängt. Richtig: R aus der Warteschlange; neu entdeckt: –; Warteschlange jetzt: S.
Lückentext
Wähl in jeder Lücke das passende Wort und prüf dann deine Antworten.
Eine Adjazenzmatrix für 5 Knoten hat . Die Breitensuche nimmt den ersten Knoten der Warteschlange, seine neu entdeckten Nachbarn werden angehängt. Ein Netzbetreiber will mehrere Städte mit möglichst wenig Kabel verbinden. Dafür berechnet man einen minimalen Spannbaum, zum Beispiel mit dem Algorithmus von .
Karteikasten
Erst selbst überlegen, dann umdrehen.
Übung mit Feedback