Durchläufe durch Graphen SS12

Aus ProgrammingWiki
< AuK
Archivierte Version vom 2012-05-12T14:57:47+00:00. Aktuelle Version

Inhaltsverzeichnis

Der Graphendurchlauf (engl. graph traversal) bildet die Grundlage vieler Graphenalgorithmen. Die Idee besteht darin, alle Knoten bzw. Kanten in einem Graphen systematisch zu besuchen, um beispielsweise Informationen über dessen Struktur zu sammeln.

Croxeldyffic_Labyrinth02.png
Ein Labyrinth mit Startpunkt (grün) und Ziel (rot)

Als Motivation für die Lösung dieses Problems soll folgendes Beispiel dienen: Eine Person befindet sich in einem Labyrinth, und sucht einen Ausgang, indem sie alle möglichen Kreuzungen von Gängen in Augenschein nimmt. Übertragen auf die Graphentheorie, existieren hierfür zwei bekannte algorithmische Lösungsverfahren, die Hauptgegenstand dieser Vorlesung sind. In unserem Beispiel sind die Gänge des Labyrinths die Kanten und alle Kreuzugen die Knoten des Graphen.

Stellen wir uns vor, die eingeschlossene Person folgt einem bestimmten Gang solange, bis sie in eine Sackgasse gerät, zur letzten Kreuzung zurückkehrt und einem anderen Weg auf die gleiche Art verfolgt. Dieses systematische Vordringen in die "Tiefe" nennen wir Tiefensuche. Sucht jedoch eine Gruppe von Leuten den Ausgang, so ist es wahrscheinlicher, dass sie gemeinsam vom Startpunkt ausschwärmen in die "Breite" vordringen. Analog dazu sprechen wir von einer Breitensuche.

Am Ende des Kapitels wird es uns möglich sein, das Labyrinth-Problem mithilfe der beiden Algorithmen zu lösen.

Note: Durchlauf (traversal) $\neq$ Suche (search)!
Achso, und laby etwas einfacher, vllt #6, zu demo-zwecken...
Applets:
//note to self2: applet: http://www.cosc.canterbury.ac.nz/mukundan/dsal/GraphAppl.html meh~
//note to self2.1: dfs-applet: http://www.lupinho.net/lupinho.de/gishur/html/DFSApplet.html
//note to self2.2: bfs-applet: http://www.lupinho.net/lupinho.de/gishur/html/BFSApplet.html
//w00t~
//note to self3: eu/hm-applets zum knobeln: http://www.cut-the-knot.org/Curriculum/Combinatorics/GraphPractice.shtml
//note to self4: laby-applet: http://www.swisseduc.ch/informatik/diskrete_mathematik/tiefensuche_labyrinth/applet.html

Info

Traversal simply means moving from one node to the next. Generally one searches by traversing the list, comparing each node's data with a given datum, either to return a pointer to a single matching node, or to return a list of matching nodes (copied from the list being searched), or simply to collect data about the matching nodes (such as a count of all the matching nodes).


Wiederholung

Zum Verständnis der später vorgestellten Graphenalgorithmen sind grundlegende Kenntnisse über Graphen und spezielle Datenstrukturen notwendig, die jedoch bereits Themen in vorigen Veranstaltungen waren und im Folgenden nur aufgefrischt werden sollen.

Graphrepräsentation

\rightarrow siehe Vorlesung Graphrepräsentation

Kontrollfragen:

      
  1. Was ist der Unterschied zwischen gerichteten und ungerichteten Graphen?
         
    Lösung
           

      In einem ungerichteten Graphen kann eine Kante (u,v) in beliebiger Richtung überquert werden, während in einem gerichteten Graphen die zulässige Durchlaufrichtung durch einen Pfeil gekennzeichnet ist (ähnlich einer Einbahnstraße).

      Will man einen ungerichteten Graphen gerichtet darstellen, so verdoppelt sich die Kantenmenge, d.h. enthält die Kantenmenge K des ungerichteten Graphen die Kante (u,v), muss die Kantenmenge K des gerichteten Graphen die Kanten (u,v) und (v,u) enthalten.

             
           
        
    1. Welche Darstellungsformen für Graphen gibt es?
      1. Wie können diese im Computer realisiert werden?
      2. Welche ist am besten?
      Lösung
           
        • Feld: Ein Adjazenzfeld ist eine sehr einfache Darstellungsform, in der alle Zielknoten in einem Array geordnet nach Startknoten gespeichert werden.
        • Liste: Eine Adjazenzliste ist eine verkettete Liste mit Nachfolgern bzw. Nachbar eines Knotens.
        • Matrix: Eine Adjazenzmatrix ist ein mehrdimensionales (V \times V mit V als Knotenanzahl) Array mit booleschen Variablen, in der a[u,v] auf 1 oder true gesetzt wird, wenn eine Kante (u,v) existiert. Analog dazu gibt eine Inzidenzmatrix (V \times E-großes Array) die Inzidenzbeziehungen zwischen Knoten und Kanten in einem Graphen an.
      1. Wir vergleichen die drei bzw. vier Darstellungsformen miteinander:
        
        
        
        
        
      Adjazenzfeld Adjazenzliste Adjazenzmatrix Inzidenzmatrix
      Speicheraufwand \mathcal{O}\: (|V| + |E|) \mathcal{O}\: (|V| + |E|) \mathcal{O}\: (|V|^2) \mathcal{O}\: (|V| \cdot |E|)
      Nachbarabfrage \mathcal{O}\: (d)^*
      * d = max. Ausgangsgrad
      \mathcal{O}\: (d)^*
      * d = max. Ausgangsgrad
      \mathcal{O}\: (1) \mathcal{O}\: (|E|)
      Vorteile + kompakte Darstellung
      &nbsp &nbsp &nbsp
      Nachteile - nur für statische Graphen &nbsp &nbsp &nbsp
              
           
           

    Bäume und Preorder-Traversierung

    \rightarrow siehe Vorlesung Sortierte Folgen

    Datenstrukturen Stack und Queue

    \rightarrow siehe Vorlesung Prioritätswarteschlangen

    Kontrollfragen:

        
    1. Nach welchem Prinzip arbeitet eine Warteschlange?
      Lösung
        
    2. Nach welchem Prinzip arbeitet ein Stack?
    3. Lösung
           

    Grundlagen zum Graphendurchlauf

    Allgemeiner Durchlauf-Algorithmus

    Um alle Knoten in einem Graphen durchlaufen und am Ende eine vernünftige Durchlaufordnung angeben zu können, überlegen wir uns folgendes Verfahren:

      
  2. Eingaben: Graph G als Adjazenzlisten- oder -matrixdarstellung, eine Menge von Knoten mit den Zuständen unbesucht und besucht und eine Arbeitsliste L, die besuchte aber noch nicht abgearbeitete Knoten beinhaltet.
  3. Algorithmus:
    1. Initialisierung: nur der Startknoten v ist mit besucht markiert und befindet sich in der Arbeitsliste L
    2. solange L nicht leer ist:
      1. wähle einen Knoten v aus L
      2. wähle und markiere einen unbesuchten Nachbarn u von v als besucht und speichere u in die Arbeitsliste L
      3. besitzt v keine unbesuchte Nachbarn, entferne v aus L

    Algorithmus: Graphendurchlauf_allgemein (Graph G, Knoten v \in V(G), Arbeitsliste L)
    \begin{array}{l|l} 1 & v \leftarrow besucht\\ 2 & L \leftarrow L \oplus v\\ 3 & \mathbf{while}\; (L \neq\: \emptyset)\; \mathbf{do} \\ 4 &\;\;\;\;\; \text{\small waehle Knoten } v \in L \\ 5 &\;\;\;\;\;\; \mathbf{if}\; (\!\text{\small es gibt } u \in V(G) \text{\small mit } u=Nachbar\; von\; v \text{\small und } u=unbesucht)\; \mathbf{then} \\ 6 &\;\;\;\;\;\;\;\;\;\;\;\; u \leftarrow besucht\\ 7 &\;\;\;\;\;\;\;\;\;\;\;\; L \leftarrow L \oplus u\\ 8 &\;\;\;\;\;\; \mathbf{else}\; L \leftarrow L \ominus u \\ \end{array}
    end Graphendurchlauf_allgemein

  4. Unsere interne Graphenrepräsentation

    • definitionen von graph, vertex, edge und was sonst nicht alles
    • kleine demonstrationen

    Tiefensuche

    • allgemeines

    Iterativ mit Stack

    Rekursiver Tiefen-Durchlauf-Algorithmus

    Um alle Knoten in einem Graphen durchlaufen und am Ende eine vernünftige Durchlaufordnung angeben zu können, überlegen wir uns folgendes Verfahren:

    • Eingaben:
          
      1. Graph G als Adjazenzlisten- oder -matrixdarstellung
      2. Eine Menge von Knoten mit den Zuständen:
        1. farbe=weiss für unbesuchte Knoten
        2. farbe=grau für besuchte Knoten
        3. farbe=schwarz für abgeschlossene Knoten

        4. pi=nil (der Vorgänger)
        5. d[u]=0 (die Zeit der Entdeckung)
        6. f[u]=0 (die Zeit des Abschließens)
    • Algorithmus:
      1. Initialisierung: alle Knoten V(G) werden mit weiss und nil belegt, zeit=0
      2. solange L nicht leer ist:
        1. wähle einen Knoten v aus L
        2. wähle und markiere einen unbesuchten Nachbarn u von v als besucht und speichere u in die Arbeitsliste L
        3. besitzt v keine unbesuchte Nachbarn, entferne v aus L

      Algorithmus: Graphendurchlauf_allgemein (Graph G, Knoten v \in V(G), Arbeitsliste L)
      \begin{array}{l|l} 1 & v \leftarrow besucht\\ 2 & L \leftarrow L \oplus v\\ 3 & \mathbf{while}\; (L \neq\: \emptyset)\; \mathbf{do} \\ 4 &\;\;\;\;\; \text{\small waehle Knoten } v \in L \\ 5 &\;\;\;\;\;\; \mathbf{if}\; (\!\text{\small es gibt } u \in V(G) \text{\small mit } u=Nachbar\; von\; v \text{\small und } u=unbesucht)\; \mathbf{then} \\ 6 &\;\;\;\;\;\;\;\;\;\;\;\; u \leftarrow besucht\\ 7 &\;\;\;\;\;\;\;\;\;\;\;\; L \leftarrow L \oplus u\\ 8 &\;\;\;\;\;\; \mathbf{else}\; L \leftarrow L \ominus u \\ \end{array}
      end Graphendurchlauf_allgemein

    Breitendurchlauf/ -suche

    Iterative Tiefensuche (Kombination)

    Anwendung/ weiterführende Themen

    Topologisches Sortieren

    Euler und Hamilton

    Starke Zusammenhangskomponenten

    TSP und CPP


    Java-Test