Wir müssen also überlegen: Implementierung der Knoten, Implementierung der Kanten, daraus: Implementierung des Graphen insgesamt. Annahme: die Knoteninhalte.

Slides:



Advertisements
Ähnliche Präsentationen
Vorbereitung: struct knoten { int x; struct knoten *l, *r; } *b, *bh, **bp; b: Zeiger auf Wurzel bh: Hilfszeiger bp: Zeiger auf Zeiger auf knoten b bp.
Advertisements

Klassen - Verkettete Liste -
Objektorientierte Programmierung
Claudio Moraga; Gisbert Dittrich
7. Natürliche Binärbäume
Gliederung Motivation / Grundlagen Sortierverfahren
Sortieren mit Binären Bäumen
Java: Dynamische Datentypen
Sortierverfahren Richard Göbel.
FH-Hof Verwaltung von Zeichenketten Richard Göbel.
Indirekte Adressierung
FH-Hof Verwaltung von Zeichenketten Richard Göbel.
Strukturen. In einer Struktur kann eine beliebige Anzahl von Komponenten (Daten) mit unterschiedlichen Datentypen (im Gegensatz zu Feldern) zusammengefaßt.
Polymorphie (Vielgestaltigkeit)
Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (21 – Kürzeste Wege) T. Lauer.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (05 – Elementare Datenstrukturen) Prof. Th. Ottmann.
Informatik II, SS 2008 Algorithmen und Datenstrukturen Vorlesung 6 Prof. Dr. Thomas Ottmann Algorithmen & Datenstrukturen, Institut für Informatik Fakultät.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 9 Claudio Moraga; Gisbert Dittrich FBI Unido
Universität Dortmund, Lehrstuhl Informatik 1 EINI II Einführung in die Informatik für Naturwissenschaftler und Ingenieure.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 7 Claudio Moraga, Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 12 Claudio Moraga, Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 10 Claudio Moraga; Gisbert Dittrich FBI Unido
Klausur „Diskrete Mathematik II“
Diskrete Mathematik I Vorlesung 6 Binärer Suchbaum II.
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer Diskrete Mathematik I Vorlesung Listen-
PKJ 2005/1 Stefan Dissmann Methoden (Motivation) Idee: Identische Programmabschnitte zusammenfassen und mit einem Namen versehen Vorteile: Übersichtlichkeit.
PKJ 2005/1 Stefan Dissmann Ausblick Es fehlen noch: Möglichkeiten zum Strukturieren größerer Programme Umgang mit variabler Zahl von Elementen Umgang mit.
PKJ 2005/1 Stefan Dissmann Rückblick auf 2005 Was zuletzt in 2005 vorgestellt wurde: Klassen mit Attributen, Methoden und Konstruktoren Referenzen auf.
Zusammenfassung Vorwoche
Die Methode public Knoten einfuegenVor (Datenelement dNeu, Datenelement dVergleich) public Knoten einfuegenVor(Datenelement dNeu, Datenelement dVergleich){
Arrays,Strings&Pointer in C/C++
DVG Klassen und Objekte
Planung einfache Dateibehandlung (externe Dateien, Öffnen, Lesen/Schreiben, Schließen). Diskussion des Problems, die Wörter in einem gegebenen Text.
Weiteres Programm Studium des Breitendurchlaufs Hierzu
Einfach verkettete Listen
PRJ 2007/1 Stefan Dissmann Verkettete datenstruktur: Liste Problem: Liste, die eine beliebige Zahl von Elementen verwaltet Operationen: Erzeugen, Anfügen,
Einführung in die Programmierung
Abteilung für Telekooperation Übung Softwareentwicklung 1 für Wirtschaftsinformatik Dr. Wieland Schwinger
Einführung in die Programmiersprache C 3.Tag Institut für Mathematische Optimierung - Technische Universität Braunschweig.
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
Einführung in die Programmierung Wintersemester 2008/09 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Einführung in die Programmierung Wintersemester 2009/10 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Einführung in die Programmierung Wintersemester 2011/12 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Einführung in die Programmiersprache C 4
Vom Umgang mit Daten. public void myProgram() { int[] saeulenWerte = new int[world.getSizeX()]; for (int i = 0; i < saeulenWerte.length; i++) { saeulenWerte[i]
CuP - Java Neunte Vorlesung Entspricht Kapitel 4.2 und 5 des Skriptums
1 // 13_2_ADT_Unger_Graph // ungerichteter, knotenmarkierter Graph als ADT // #include struct Knoten { public: void Erzeuge_Kn (int, char*); char* Get_Marke.
Binärer Suchbaum IV AVL-Baum I
Institut für Kartographie und Geoinformation Diskrete Mathematik I Vorlesung Binärer Suchbaum I-
Funktionen, Felder und Parameter- übergabe. Funktionsaufruf mit Feld als Parameter: Parameter = Name des Feldes.
1 // Verkettete Liste 2 // demonstriert verkettete Listen und // Rekursion // (Einfügen am "Fuß") // #include struct Liste { int Element; Liste *weiter;
Tutorium Software-Engineering SS14 Florian Manghofer.
Pointer, Arrays und verkettete Listen. Mehrdimensionale Arrays  Pointer auf ein Array von Pointern  int32 **matrix = new int32*[3];  matrix: Zeiger.
Tutorium Software-Engineering SS14 Florian Manghofer.
Pointer. * und &  Bei der Definition int var1; ○ // „normale“ Variable int *var2; ○ // Zeiger auf einen Integer int *var2 = NULL; ○ // … incl. Initialisierung.
Implementieren von Klassen
3. Die Datenstruktur Graph 3.2 Repräsentation von Graphen
1. Die rekursive Datenstruktur Liste 1
 Präsentation transkript:

Wir müssen also überlegen: Implementierung der Knoten, Implementierung der Kanten, daraus: Implementierung des Graphen insgesamt. Annahme: die Knoteninhalte sind Zeichenketten (Vereinfachung - Knoteninhalte können beliebig komplex sein). Zunächst: Operationen auf Knoten

Prinzip: Information Hiding (Verbergen von Informationen). Allgemein: Information sollten von Benutzern einer Struktur nur gelesen werden können. Änderungen sollten durch Funktions- aufrufe kontrollierbar sein. Grund: Programme als Kontrakt zwischen Aufrufern und Akteuren, zwischen Aufrufern und Akteuren, die Aufrufer garantieren Eigenschaften von Werten, die Aufrufer garantieren Eigenschaften von Werten, die Akteure garantieren wohldefiniertes Verhalten, die Akteure garantieren wohldefiniertes Verhalten, Das geht nur durch Kontrolle des Zugriffsverhaltens.

Konsequenzen: Daten in einer struct möglichst private Zugriff: lesend und schreibend durch geeignete Funktionen. struct Bsp { int a; char b; }; struct Bsp { int a; char b; }; Es sei deklariert: Bsp X; X.a = 1 und cout << X.a sind möglich, also schreibender und lesender Zugriff.

Insbesondere kann jedes Programm, das auf X zugreifen kann, X.a ändern, ohne daß X selbst davon erfährt. struct Bsp2 { private: int a; public: Setze(int); int Lese(); char b; }; struct Bsp2 { private: int a; public: Setze(int); int Lese(); char b; }; Bsp2 Y Deklariere Bsp2 Y; Y.a Y.a ist illegal und wird vom Compiler zurückgewiesen.

struct Bsp2 { private: int a; public: void Setze(int); int Lese(); char b; }; void Bsp2::Setze(int x) { a = x; } int Bsp2::Lese() { return a; } struct Bsp2 { private: int a; public: void Setze(int); int Lese(); char b; }; void Bsp2::Setze(int x) { a = x; } int Bsp2::Lese() { return a; } Bsp2 Y sei deklariert. Y.a Y.a ist ein illegaler Ausdruck, Y.b Y.b dagegen nicht, Y.a Y.Lese(), Y.Setze(33). Zugriff auf Y.a lesend nur durch Y.Lese(), schreibend (also verändernd) nur durch Y.Setze(33).

Konsequenz: wenn die Inhalte der Knoten des Graphen nicht von außen (d.h. durch beliebige Benutzer) geändert werden sollen, so sollte der Inhalt als private deklariert werden. Weiterhin sind Definitions- und Leseoperationen notwendig. struct Knoten { private: char * Inhalt;....public: void SetzeWert(char *); char * LeseWert();....}; Inhalt: Zeichenkette unbestimmter Länge Weitere Felder

void Knoten::SetzeWert(char *s) { for (int j = 0; s[j++] != '\0'; ); Inhalt = new char [--j]; Inhalt = s;...} char * Knoten::LeseWert() {return Inhalt;} Stelle Länge der Zeichenkette fest Verschaffe mir ein entsprechend großes Feld. Zuweisung

int Gleich(Knoten *); Weitere Operationen: Gegeben ein Knoten, möchte feststellen, ob sein Inhalt gleich dem des aktuellen Knotens ist: int Knoten::Gleich(Knoten * K) { int strcmp(char *, char *); return (strcmp((*K).Inhalt, Inhalt) == 0? true: false); true: false);} Die üblichen Konstanten Alter Bekannter

Die Adjazenzlisten zu einem Knoten werden in einer verketteten Liste verwaltet. Ergibt ein private Attribut Adjazenz mit entsprechenden Funktionen: struct Knoten { private: char * Inhalt; Knoten * Adjazenz;...public: void SetzeWert(char *); char * LeseWert(); int Gleich(Knoten *);... Knoten * LeseAdjazenz(); void SetzeAdjazenz(Knoten *); };

Knoten * Knoten::LeseAdjazenz() { return Adjazenz; } void Knoten::SetzeAdjazenz(Knoten * K) { Knoten * L = new Knoten;...;L->SetzeWert(K->LeseWert()); L->Adjazenz = Adjazenz; Adjazenz = L; } Das sollte klar sein.

Erzeuge also einen neuen Knoten L L->SetzeWert(K->LeseWert()); kopiere die Zeichenkette von K (dem Parameter) nach L : L->SetzeWert(K->LeseWert()); L->Adjazenz = Adjazenz füge L an den Anfang der Adjazenzliste des Knotens L->Adjazenz = Adjazenz Adjazenz = Ldas ist dann die Adjazenzliste des Knotens: Adjazenz = L

Schließlich werden die Knoten miteinander verkettet (Verwaltungsinformation, die nichts mit dem Graphen selbst zu tun hat). Inhalt Adjazenz Adjazenz - liste * Ver-waltung*

struct Knoten { private: char * Inhalt; Knoten * Adjazenz; Knoten * Verwaltung; public: void SetzeWert(char *); char * LeseWert(); int Gleich(Knoten *); Knoten * LeseVerwaltung(); Knoten * LeseAdjazenz(); void SetzeVerwaltung(Knoten *); void SetzeAdjazenz(Knoten *); void Druck(char *, char *); }; Vollständige Definition von Knoten:

Knoten * Knoten::LeseVerwaltung() { return Verwaltung; } void Knoten::SetzeVerwaltung(Knoten * K) { K->Verwaltung = Verwaltung; Verwaltung = K; } (ist wieder trivial) Setze den neuen Knoten an den Anfang der Verwaltungsliste

Drucken Schließlich: Drucken void Knoten::Druck(char * vor, char * nach) { *ausgabe << vor << Inhalt << nach; } Datei für die Ausgabe Texte, in denen der Inhalt Inhalt eingebettet werden kann (z. B. \t\n \t oder \n )

Sozusagen Basisschicht im Schichtenmodell: Definition von Knoten und ihrer Grundoperationen Definition des Graphen und seiner Grundoperationen eine klitzekleine Zwischenschicht

Zwischenschicht dient zur Realisierung von hilfreichen Operationen auf Knoten des Graphen Operationen sind freilich nicht so vital für die Knoten, daß sie in die Knoten-Definition aufhgenommen werden müßten. es handelt sich dabei um: Finden eines Knoten in der Verwaltungsliste eines anderen, Einfügen eines Knoten in dieser Liste, Finden eines Knoten in der Adjazenzliste eines anderen, Drucken der Adjazenzliste eines Knoten.

int VerwFinde(Knoten *K, Knoten *L) { if (L == NULL) return false; else return (K->Gleich(L) ? true: return (K->Gleich(L) ? true: VerwFinde(K, L->LeseVerwaltung())); VerwFinde(K, L->LeseVerwaltung()));} Knoten * VerwEinfuegen(Knoten * K, Knoten * L){ int VerwFinde(Knoten *, Knoten *); if (!VerwFinde(K, L)) K->SetzeVerwaltung(L); return K; }

int AdjFinde(Knoten *K, Knoten *L) { if (L == NULL) return false; else return (K->Gleich(L) ? true: AdjFinde(K, L->LeseAdjazenz())); AdjFinde(K, L->LeseAdjazenz()));} void ListenDruck(Knoten *L) { if (L == NULL) *ausgabe << "}," << endl; else { *ausgabe LeseWert() LeseWert() << (L->LeseAdjazenz() == NULL (L->LeseAdjazenz() == NULL ? "" : ", "); ? "" : ", "); ListenDruck(L->LeseAdjazenz()); }}

Analoges Vorgehen bei der Formulierung des Graphen: private welche Komponenten sind private ? welche Operationen werden benötigt? private Hilfsoperationen wieder versteckt, damit zweifache Funktion der private -Deklaration: Schützen vor unberechtigtem Zugriff, Verbergen von Funktionen, die nicht außerhalb eines wohldefinierten lokalen Kontexts aufgerufen werden sollten.

Der Graph besteht zunächst aus einem Zeiger auf einen Knoten (ähnlich der Wurzel bei binären Suchbäumen) und der Initialisierung: struct Graph { private: Knoten * EinKnoten;...public: void Init();...};

Ein Knoten? (Ganz Gallien?) Über die Verwaltungsinformation werden alle anderen Knoten eingefügt. void Graph::Init() { EinKnoten = NULL; } Die Initialisierung ist ziemlich trivial:

Hilfsfunktion: Nachsehen, wo ein Knoten auf der Verwaltungsliste eines anderen steckt; ein Zeiger auf diesen Knoten wird zurückgegeben. Wird als private vereinbart, da nur lokal verwendet. Knoten * Graph::DaIstDerKnoten(Knoten * K, Knoten * Wo) { Knoten * Wo) { if (Wo == NULL) if (Wo == NULL) return NULL; return NULL; else if (K->Gleich(Wo) == true) else if (K->Gleich(Wo) == true) return Wo; return Wo; else else return return DaIstDerKnoten(K, DaIstDerKnoten(K, Wo->LeseVerwaltung()); Wo->LeseVerwaltung()); }

Weiter: Testfunktionen ist ein Knoten mit einem bestimmten Inhalt im Graphen vorhanden? sind zwei Knoten mit einer Kante verbunden? int Graph::KnotenTesten(Knoten * K) { if (DaIstDerKnoten(K, EinKnoten) != NULL ?) return true; else return false; }

int Graph::KanteTesten(Knoten * K, Knoten * L) { Knoten * OK = DaIstDerKnoten(K, EinKnoten); return (OK == NULL ? false : AdjFinde(OK, L)); } Also: suche den Knoten K in der Verwaltungsliste von EinKnoten, ist der Knoten nicht vorhanden (d.h. wird NULL zurück- gegeben), kann keine Kante vorhanden sein, sonst: suche in der Adjazenzliste des Resultatknotens nach dem Knoten L.

Stand der Dinge: struct Graph { private: Knoten * EinKnoten; Knoten * DaIstDerKnoten(Knoten *, Knoten *); Knoten *);public: void Init(); int KnotenTesten(Knoten *); int KanteTesten(Knoten *, Knoten *);...};

void Graph::KnotenEinfuegen(Knoten * K) { if (EinKnoten == NULL) EinKnoten = K; else if (!KnotenTesten(K)) EinKnoten->SetzeVerwaltung(K);} Ziemlich kanonisch: Einfügen von Knoten und Kanten: Sehe nach, ob überhaupt schon ein Knoten vorhanden ist. Nur falls der Knoten noch nicht vorhanden ist, wird er in die Verwaltungsliste eingefügt.

void Graph::KanteEinfuegen(Knoten *K, Knoten *L) { if (!KnotenTesten(K)) KnotenEinfuegen(K); if (!KnotenTesten(L)) KnotenEinfuegen(L); if (!KanteTesten(K, L)) { K->SetzeAdjazenz(L); L->SetzeAdjazenz(K); L->SetzeAdjazenz(K);}} Einfügen einer Kante zwischen zwei Knoten: Schaue nach, ob die Knoten überhaupt schon vorhanden sind, füge sie ggf. ein. Überprüfe, ob die Kante bereits vorhanden ist, sonst setze die beider Adjazenzfelder beider Knoten entsprechend.

Schließlich, als Hilfsfunktionen: Konstruiere aus einer Zeichenkette einen neuen Knoten im Graphen (MkKnoten), Druck des gesamten Graphen.

Knoten * Graph::MkKnoten(char * s) { Knoten * K = new Knoten, * L; K->SetzeWert(s); L = DaIstDerKnoten(K, EinKnoten); return (L == NULL ? K : L); } Konstruiere einen Knoten mit dem Inhalt-Feld Schaue nach, ob ein Knoten mit diesem Inhalt bereits im Graphen vorhanden ist Setze Rückgabewert entsprechend

Drucken: drucke jeden Knoten, drucke für jeden Knoten seine Adjazenzliste (kommt aus der Zwischenschicht). void Graph::Druck(char * vor, char * nach) { void ListenDruck(Knoten *); for (Knoten * K = EinKnoten; K != NULL; K = K->LeseVerwaltung()) { K = K->LeseVerwaltung()) { *ausgabe Druck(vor, nach); ListenDruck(K->LeseAdjazenz());}}

Insgesamt sieht die struct so aus: struct Graph { private: Knoten * EinKnoten; Knoten * DaIstDerKnoten(Knoten *, Knoten *); Knoten *);public: void Init(); Knoten * MkKnoten(char *); int KnotenTesten(Knoten *); int KanteTesten(Knoten *, Knoten *); void KnotenEinfuegen(Knoten *); void KanteEinfuegen(Knoten *, Knoten *); void Druck(char *, char *); };

void main() { Graph * G = new Graph; char * ara[] = {"\t", "eins", "zwei", "drei", "vier", "vier", "fünf", "sechs", "sieben"}; "fünf", "sechs", "sieben"}; Knoten * MkKnoten(char *), * K[8]; G->Init(); for (int i = 1; i < 8; i++) K[i] = G->MkKnoten(ara[i]); G->KanteEinfuegen(K[1], K[2]); G->KanteEinfuegen(K[1], K[2]); G->KanteEinfuegen(K[6], K[7]); G->KanteEinfuegen(K[6], K[7]); G->Druck("", ") = {"); G->Druck("", ") = {");} (Beispielgraph)

Ausgabe: ADJ(eins) = {sieben, sechs, zwei}, ADJ(sieben) = {sechs, fünf, vier, drei, zwei, eins}, ADJ(sechs) = {sieben, eins, fünf}, ADJ(fünf) = {sieben, sechs, vier}, ADJ(vier) = {sieben, fünf, drei}, ADJ(drei) = {sieben, vier, zwei}, ADJ(zwei) = {sieben, drei, eins}, Programm: prog-25.cpp