graphen:start
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
graphen:start [2023/10/05 20:16] – Martin Pabst | graphen:start [2023/10/13 07:12] (aktuell) – [Warteschlange (Queue)] Martin Pabst | ||
---|---|---|---|
Zeile 38: | Zeile 38: | ||
- | ===== Adjazenzmatrix ===== | ||
- | <WRAP center round info 80%> | ||
- | Die oben verwendete graphische Darstellung ist zwar anschaulich, | ||
- | * 0, wenn es keine Kante zwischen dem links stehenden und dem oben stehenden Knoten gibt | ||
- | * 1, wenn es eine Kante zwischen den Knoten gibt und der Graph ungewichtet ist | ||
- | * ansonsten das Kantengewicht | ||
- | </ | ||
- | ==== Beispiel 2 ==== | ||
- | (Adjazenzmatrix eines gerichteten Graphen) \\ | ||
- | {{ : | ||
- | ^ ^ Knoten 1 ^ Knoten 2 ^ Knoten 3 ^ | ||
- | ^ Knoten 1 | 0 | 0 | 1 | | ||
- | ^ Knoten 2 | 1 | 0 | 0 | | ||
- | ^ Knoten 3 | 0 | 0 | 0 | | ||
- | ==== Beispiel 3 ==== | ||
- | {{ : | ||
- | ^ ^ Knoten 1 ^ Knoten 2 ^ Knoten 3 ^ | ||
- | ^ Knoten 1 | 0 | 22 | 17 | | ||
- | ^ Knoten 2 | 22 | 0 | 0 | | ||
- | ^ Knoten 3 | 17 | 0 | 0 | | ||
- | Die Adjazenzmatrix eines ungerichteten Graphen ist immer **symmetrisch bzgl. der Diagonale** von links oben nach rechts unten. | ||
- | ==== Aufgabe 4 ==== | ||
- | Modellieren Sie den folgenden Graphen als Adjazenzmatrix. | ||
- | {{ : | ||
- | [[.aufgabe4loesung: | ||
- | ==== Aufgabe 5 ==== | ||
- | Zeichne eine graphische Darstellung des durch die folgende Adjazenzmatrix gegebenen Graphen: | ||
- | ^ ^ A ^ B ^ C ^ D ^ E ^ | ||
- | | A | | 8 | | 5 | | | ||
- | | B | | ||
- | | C | | 2 | | 4 | 1 | | ||
- | | D | 5 | | ||
- | | E | | ||
- | [[.aufgabe5loesung: | ||
- | ===== Modellierung von Graphen durch Adjazenzmatrizen ===== | ||
- | Graphen werden in Java-Programmen oft implementiert, | ||
- | <WRAP center round info 60%> | ||
- | **Zweidimensionales int-Array? | ||
- | Du erinnerst Dich vielleicht noch an eindimensionale Arrays, z.B. | ||
- | <code java> | ||
- | int[] zahlen = new int[7]; | ||
- | zahlen[0] = 12; // speichert im ersten Element die Zahl 12 | ||
- | zahlen[5] = 4; // speichert im 6. Element die Zahl 4; | ||
- | println(zahlen[5]); | ||
- | </ | ||
- | Falls Du Dein Wissen über Arrays auffrischen möchtest, [[https:// | ||
- | Hier zur Wiederholung eine [[.fingeruebungarrays: | ||
- | Ein **zweidimensionales** Array speichert "ein Schachbrett voller Zahlen" | ||
- | < | ||
- | int[][] zahlen = new int[4][3]; | ||
- | zahlen[2][1] = 10; | ||
- | zahlen[0][2] = 14; | ||
- | </ | ||
- | Man kann sich vorstellen, dass das Array '' | ||
- | ^**zahlen**^**0**^**1**^**2**^ | ||
- | ^**0**|0|0|14| | ||
- | ^**1**|0|0|0| | ||
- | ^**2**|0|10|0| | ||
- | ^**3**|0|0|0| | ||
- | Im Array gespeichert sind natürlich nur die 12 Werte der blauen Zellen. Die fettgedruckten Zeilen- bzw. Spaltenköpfe dienen nur zur Veranschaulichung. | ||
- | </ | ||
- | |||
- | ==== Beispiel 4 - Speicherung eines gerichteten Graphen ==== | ||
- | {{ : | ||
- | Das folgende Programm speichert den Graphen rechts als Adjazenzmatrix: | ||
- | < | ||
- | |||
- | <div class=" | ||
- | |||
- | <script type=" | ||
- | int[][] matrix = new int[4][4]; | ||
- | matrix[0][1] = 1; | ||
- | matrix[1][0] = 1; | ||
- | matrix[1][2] = 1; | ||
- | matrix[2][3] = 1; | ||
- | matrix[3][1] = 1; | ||
- | |||
- | for(int i = 0; i < 4; i++) { | ||
- | | ||
- | print(matrix[i][j] + " "); | ||
- | } | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | </ | ||
- | </ | ||
- | |||
- | ===== Die Klasse Graph ===== | ||
- | Wir entwickeln eine Klasse '' | ||
- | <WRAP center round tip 80%> | ||
- | Den im Testprogramm unten generierten Graphen siehst Du in graphischer Darstellung links neben dem Programmkasten. So kannst Du das Programm schrittweise ausführen und gleichzeitig den Programmverlauf am Graphen mitverfolgen. | ||
- | </ | ||
- | |||
- | |||
- | < | ||
- | <div class=" | ||
- | |||
- | <script type=" | ||
- | public class Graph { | ||
- | | ||
- | |||
- | | ||
- | adj = new int[anzahlKnoten][anzahlKnoten]; | ||
- | } | ||
- | | ||
- | | ||
- | adj[von][nach] = 1; | ||
- | } | ||
- | | ||
- | | ||
- | return istVerbundenRekursiv(startknoten, | ||
- | } | ||
- | |||
- | | ||
- | schonBesucht[startknoten] = true; | ||
- | println(" | ||
- | |||
- | if(startknoten == zielknoten) { | ||
- | | ||
- | } | ||
- | for(int i = 0; i < adj.length; i++) { | ||
- | | ||
- | if(istVerbundenRekursiv(i, | ||
- | | ||
- | } | ||
- | } | ||
- | } | ||
- | return false; | ||
- | } | ||
- | |||
- | } | ||
- | </ | ||
- | |||
- | <script type=" | ||
- | Graph g = new Graph(8); | ||
- | g.kanteHinzufügen(0, | ||
- | g.kanteHinzufügen(1, | ||
- | g.kanteHinzufügen(1, | ||
- | g.kanteHinzufügen(2, | ||
- | g.kanteHinzufügen(3, | ||
- | g.kanteHinzufügen(2, | ||
- | g.kanteHinzufügen(4, | ||
- | g.kanteHinzufügen(3, | ||
- | g.kanteHinzufügen(5, | ||
- | g.kanteHinzufügen(5, | ||
- | g.kanteHinzufügen(1, | ||
- | g.kanteHinzufügen(6, | ||
- | g.kanteHinzufügen(7, | ||
- | println(g.istVerbunden(4, | ||
- | </ | ||
- | |||
- | |||
- | </ | ||
- | </ | ||
- | |||
- | <WRAP center round todo 80%> | ||
- | **Aufgaben: | ||
- | * Erstelle eine Methode '' | ||
- | < | ||
- | 0 1 0 | ||
- | 1 0 1 | ||
- | 0 1 0 | ||
- | </ | ||
- | * Erstelle eine Methode '' | ||
- | |||
- | </ | ||
- | |||
- | ===== Tiefensuche ===== | ||
- | Wir wollen eine Methode '' | ||
- | * 1.) Überprüfe, | ||
- | * 2.) Überprüfe für jeden von '' | ||
- | Dieses Vorgehen kann bei zyklischen Graphen zu einer **unendlichen Methodenaufrufkette** führen. Daher muss der Algorithmus **speichern, | ||
- | |||
- | <WRAP center round info 80%> | ||
- | Die Methode folgt einem **uninformierten** Suchverfahren (uninformiert bedeutet hier, dass dem Verfahren über die Einträge der Adjazenzmatrix hinaus keine weiteren Informationen zur Verfügung stehen) mit dem Namen **Tiefensuche** (engl. depth-first search, DFS). "Bei der Tiefensuche wird zunächst jeder Pfad vollständig in die Tiefe beschritten, | ||
- | Ein zweites uninformiertes Suchverfahren wäre die **Breitensuche** (engl. breadth-first search, BFS). Bei dieser werden " | ||
- | Keines der beiden Suchverfahren ist für das allgemeine Problem der Suche in Graphen „besser“ geeignet als das andere. | ||
- | </ | ||
- | |||
- | {{ : | ||
- | |||
- | ==== Beispiel für Tiefen- und Breitensuche ==== | ||
- | Überprüft man in diesem Graphen, ob es eine Verbindung von Knoten 1 nach Knoten 5 gibt, so durchläuft die Tiefensuche ihn in der Reihenfolge 1,2,4,3 (Sackgasse), | ||
- | |||
- | <WRAP center round todo 60%> | ||
- | **Aufgabe (nicht leicht...): | ||
- | Erweitere das Programm so, dass die Methoden '' | ||
- | [[.istverbundenaufgabe: | ||
- | </ | ||
- | |||
- | |||
- | ===== Breitensuche ===== | ||
- | Schreibe die Methode '' | ||
- | * Du wirst eine Warteschlange brauchen, die int-Werte speichern kann. In der Programmbox unten habe ich schon eine für Dich hinterlegt. | ||
- | * Ergänze dein Programm so, dass es ausgibt, welche Knoten es gerade untersucht und welche es in der Warteschlange ablegt. Vergleiche seine Ausgabe mit dem Graphen links! | ||
- | |||
- | < | ||
- | <img src="/ | ||
- | <div class=" | ||
- | |||
- | <script type=" | ||
- | public class Graph { | ||
- | | ||
- | |||
- | | ||
- | adj = new int[anzahlKnoten][anzahlKnoten]; | ||
- | } | ||
- | | ||
- | | ||
- | adj[von][nach] = 1; | ||
- | } | ||
- | | ||
- | | ||
- | // TODO! | ||
- | } | ||
- | |||
- | |||
- | } | ||
- | </ | ||
- | |||
- | <script type=" | ||
- | Graph g = new Graph(8); | ||
- | g.kanteHinzufügen(0, | ||
- | g.kanteHinzufügen(1, | ||
- | g.kanteHinzufügen(1, | ||
- | g.kanteHinzufügen(2, | ||
- | g.kanteHinzufügen(3, | ||
- | g.kanteHinzufügen(2, | ||
- | g.kanteHinzufügen(4, | ||
- | g.kanteHinzufügen(3, | ||
- | g.kanteHinzufügen(5, | ||
- | g.kanteHinzufügen(5, | ||
- | g.kanteHinzufügen(1, | ||
- | g.kanteHinzufügen(6, | ||
- | g.kanteHinzufügen(7, | ||
- | println(g.istVerbunden(4, | ||
- | </ | ||
- | |||
- | <script type=" | ||
- | class IntWert { | ||
- | |||
- | int wert; | ||
- | | ||
- | |||
- | | ||
- | this.wert = wert; | ||
- | this.nächster = nächster; | ||
- | } | ||
- | } | ||
- | |||
- | |||
- | class IntWarteschlange { | ||
- | |||
- | | ||
- | |||
- | | ||
- | if(erster == null) return -1; | ||
- | IntWert w = erster; | ||
- | erster = erster.nächster; | ||
- | return w.wert; | ||
- | } | ||
- | |||
- | | ||
- | if(erster == null) { | ||
- | | ||
- | } else { | ||
- | | ||
- | | ||
- | w = w.nächster; | ||
- | } | ||
- | | ||
- | } | ||
- | } | ||
- | |||
- | | ||
- | return erster == null; | ||
- | } | ||
- | |||
- | |||
- | } | ||
- | </ | ||
- | </ | ||
- | |||
- | </ | ||
- | |||
- | Auf der linken Seite siehst Du eine graphische Darstellung des im Hauptprogramm generierten Testgraphen. \\ \\ | ||
- | [[.breitensuche: |
graphen/start.1696536993.txt.gz · Zuletzt geändert: 2023/10/05 20:16 von Martin Pabst