Algo&Komp. - Wichtige Begriffe Mattia Bergomi 2008 Woche 2−3 1 Graphen 1.1 Definition Ein Graph ist eine (nicht so abstrakte) Struktur, die aus einer Menge von Punkten besteht, zwischen denen Linien verlaufen (z.B. ein Strassennetz, . . . ). Die Punkte nennt man Knoten, die Linien nennt man Kanten. Die genaue Definition lautet: Definition (Graph) Ein Graph G ist ein Tupel (V, E), wobei V = {v1 , . . . , vn } die Menge der Knoten ist, und E ⊆ {{vi ; vj } | vi 6= vj ∈ V } die Menge der Kanten ist. Knoten Kanten Abbildung 1: Die Zürilinie als ein Graph betrachtet Wichtig ist der Graph als Paar (V, E), nicht aber wie er gezeichnet wird: Knoten können in eine beliebige Position gezeichnet werden, Kanten können auch Kurven sein, die sich schneiden, usw.: es ist immer derselbe Graph! Auf einem Computer können Graphen als eine Adjazenzmatrix oder als eine Adjazenzliste gespeichert werden (siehe Skript 1.4.2). Laufzeiten für Suchoperationen usw. hängen auch von dieser Wahl ab. Es gibt einige Varianten von Graphen: • ungerichtet (wie im Bild 1, d.h. die Kanten sind einfach Linien) oder gerichtet (d.h. die Kanten sind jetzt Pfeilen, deren Richtungen wichtig sind). • ungewichtet (wie im Definition 1, d.h. die Kanten sind einfach Linien) oder gewichtet (Kanten haben jetzt ein Gewicht, d.h. eine zugehörige Zahl ∈ R, die z.B. die Länge, die Kosten, etc. der Kanten darstellen können). -1- Algo&Komp. - Wichtige Begriffe Mattia Bergomi 2008 Weitere Bezeichnungen/Definitionen sind: • Alle Knoten u, die mit einem Knoten v über eine Kante verbunden sind, heissen Nachbarn. Notation: Γ(v) := {alle Knoten, die Nachbarn von v sind}. • Grad von v ∈ V : deg(v) := Anzahl Kanten, die inzident mit dem Knoten v sind (d.h. “Anzahl Nachbarn von v”). • Ein Weg (der Länge L) ist eine Folge von L + 1 Knoten so, dass je zwei aufeinanderfolgende Knoten verbunden sind. • Ein Pfad ist ein Weg, der aber sich selbst nicht schneidet, d.h. die Folge von Knoten enthält nicht zweimal denselben Knoten. Ein vi -vj –Pfad ist ein Pfad, der von vi nach vj geht. • Ein Kreis ist ein Pfad, mit Startpunkt = Endpunkt. • Ein Graph heisst zusammenhängend (engl. connected), wenn von jedem Knoten jeder andere durch ein Pfad erreichbar ist. Falls nicht, dann werden alle maximalen zusammenhängenden Teile von G die Komponenten (“isolierte Inseln”) von G genannt. • Ein Baum ist ein zshg. Graph, der keinen Kreis enthält. Ein Spannbaum von G ist ein Teilgraph von G, der ein Baum ist. Ein Knoten von Grad 1 in einem Baum heisst Blatt. • Ein Graph heisst bipartit, wenn eine Partitionierung V = V1 ∪ V2 (mit V1 ∩ V2 = ∅) der Knoten existiert, so dass alle Kanten zwischen diesen zwei Mengen verlaufen (also keine Kante zwischen zwei Knoten in V1 bzw. V2 existiert). deg(v2 ) = 3 v2 Blatt v2 v5 v5 Kreise v6 v6 v1 v1 Pfad v3 v3 v4 v4 Spannbaum von G G (zshg.) V1 V2 G Bipartit Abbildung 2: Beispiel einiger Definitionen -2- Algo&Komp. - Wichtige Begriffe 1.2 Mattia Bergomi 2008 Einfache Theoreme Einige einfache Theoreme/Fakten über Graphen: • Es gilt immer: X deg(v) = 2|E|. v∈V • Es gibt immer mindestens |V | − |E| Komponenten. • Für jeden zshg. Graph G gilt: |E| ≥ |V | − 1. • Ein Baum (mit |V | ≥ 2) enthält immer mindestens zwei Blätter, und wenn man ein Blatt (oder mehrere) entfernt, dann ist das Resultat wieder ein Baum. • Wenn wir in einem zshg. Graph eine Kante in einer Zyklus entfernen, dann ist das Resultat noch zshg. • G zshg. und |E| = |V | − 1 ⇐⇒ G ist ein Baum. 2 Zwei Algorithmen zum Durchsuchen (bzw. Durchlaufen) der Knoten eines Graphens Die Algorithmen brauchen zwei spezielle Datenstrukturen, die wir zuerst vorstellen: Definition Eine Queue Q ist eine Struktur, die Objekte wie eine Warteschlange speichert: das letzte Element, das in die Queue eingefügt wird, wird auch als letztes die Queue verlassen (FIFO: First In, First Out). Dabei haben wir die zwei Operationen Q.I NSERT(v) und Q.D EQUEUE() sowie den Test Q.I S E MPTY() zur Verfügung (siehe Abbildung 3, links). Definition Ein Stack S ist eine Struktur, die Objekte wie auf einem Stapel speichert: das letzte Element, das auf den Stack gelegt wird, wird ihn als erstes verlassen (LIFO: Last In, First Out). Dabei haben wir die zwei Operationen S.P USH(v) und S.P OP() sowie den Test S.I S E MPTY() zur Verfügung (siehe Abbildung 3, rechts). Q.DEQUEUE() S.PUSH(v) S.POP() Q.INSERT(v) Queue Stack Abbildung 3: Beispiel von Queue und Stack -3- Algo&Komp. - Wichtige Begriffe 2.1 Mattia Bergomi 2008 Breitensuche (BFS) Man fixiert einen Startknoten s. Alle Knoten v werden zwei Eigenschaften bekommen: d[v] := Länge des kürzesten s-v Pfades. pred[v] := Knoten, von dem her wir v während der BFS erreicht haben. Erklärung von BFS durch ein Beispiel (siehe Abbildung 4!) • Man startet mit s und einer leeren Queue Q. (Im Beispiel: s = 1) • Man schaut alle Nachbarn von s, markiert sie mit d[v] = 1 und pred[v] = s, und fügt sie in die Queue Q ein. (Im Beispiel ist jetzt: Q = [2, 3, 4]) • Man entfernt den ersten Knoten v aus Q und für alle unbesuchten Nachbarn u (d.h. diejenige mit d[u] = ∞) setzt man d[u] = d[v] + 1 und pred[u] = v, und fügt sie in die Queue Q ein. (Im Beispiel: v = 2; u = {5, 6}; d[u] = 2; pred[u] = 2; Q = [3, 4, 5, 6]) • Man wiederholt den letzten Schritt, bis Q leer ist. Diese Prozedur ist in Abbildung 4 dargestellt. 5 2 s 1 3 4 d[v] = 1 6 7 8 9 10 d[v] = 2 Abbildung 4: Beispiel für BFS: die Zahlen entsprechen der Reihenfolge, in der die Knoten in Q eingefügt (bzw. bearbeitet) werden Die Resultate sind: → Die Laufzeit ist O (|V | + |E|). → d[v] ist die Länge eines kürzesten s-v–Pfades. Dieser Pfad ist gegeben durch die Knoten {v, pred[v], pred[pred[v]], . . . , s}. → Die Kanten {{v, pred[v]} | v 6= s} bilden einen Spannbaum T von G (und nach der obigen Eigenschaft sind alle s-v–Pfade in T kürzeste s-v–Pfade). -4- Algo&Komp. - Wichtige Begriffe 2.2 Mattia Bergomi 2008 Tiefensuche (DFS) Man fixiert einen Startknoten s. Alle Knoten v werden eine Eigenschaft bekommen: pred[v] := Knoten, von dem her wir v während der DFS erreicht haben. Erklärung von DFS durch ein Beispiel (siehe Abbildung 5!): • Man startet mit s. (Im Beispiel: s = 1) • Man geht “zufällig” vor (und speichert pred[v] für die besuchteten Knoten), bis keine Kante zu einem unbesuchten Nachbarknoten mehr existiert (wir sind “am tiefsten gegangen”). (Im Beispiel: 1 → 2 → 3) • Man kommt zurück, bis wieder unbesuchte Nachbarn existieren. (Im Beispiel: zurück zu 2) • Man geht analog wie im zweiten Schritt vorwärts, bis keine weitere Kante zu einem unbesuchten Nachbarn mehr existiert. (Im Beispiel: 2 → 4 → 5 → 6) • Man geht analog vor (zurück → “neue” Kante → “am tiefsten” → zurück → . . . ), bis zum man zu s zurück kommt und keine Nachbarn mehr unbesucht sind. Diese Prozedur ist in Abbildung 5 dargestellt. 3 2 s 1 5 7 4 6 8 9 10 Abbildung 5: Beispiel für DFS: die Zahlen entsprechen der Reihenfolge, in der die Knoten besucht werden Die Resultate sind: → Die Laufzeit ist O (|V | + |E|). → Die Kanten {{v, pred[v]} | v 6= s} bilden einen Spannbaum T von G. -5-