EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 10 Claudio Moraga; Gisbert Dittrich FBI Unido
Kap 10: Warteschlange als ADT Vorl EINI-I" Gliederung Kapitel 10 Beispiel: Warteschlange –Ansatz zur Realisierung –struct Warteschlange, Impl. von Operationen –Benutzung von "Warteschlange" Warteschlange als ADT (abstrakter Datentyp) –private - public –Neuimplementierung mit Anmerkungen –Anmerkung zu ADTs Breitensuche in binären Bäumen –unter Verwendung von Warteschlangen
Kap 10: Warteschlange als ADT Vorl EINI-I" Realisierung von Warteschlangen Arbeitsweise – Initialisierung –Einfügen von Elementen am Ende –Entfernen von Elementen am Anfang ausgezeichnete Elemente Kopf und Fuß Liste von Elementen –(möchte mich nicht am Anfang auf eine feste Anzahl von Elementen festlegen; sonst: Feld möglich)
Kap 10: Warteschlange als ADT Vorl EINI-I" Realisierung von Warteschlangen Operationen: –Einfügen am Ende –Entfernen am Anfang –Initialisierung Wunsch nach Verkapselung: –Daten und Operationen zusammen behandeln Annahme: Nutzelemente sind natürliche Zahlen. Also Listenelemente : struct IntListe { int Element; IntListe * weiter; };
Kap 10: Warteschlange als ADT Vorl EINI-I" Zur Realisierung DieListe KopfFuss struct Warteschlange { IntListe * DieListe; IntListe * Kopf, * Fuss; Einfuegen(int)IntListe * Einfuegen(int); Entfernen()IntListe * Entfernen(); Init()IntListe * Init(); DerKopf()int DerKopf(); ListenDruck(...) Warteschlange void ListenDruck (ofstream *); };
Kap 10: Warteschlange als ADT Vorl EINI-I" Konsequenz Kapselung: Gemeinsames Deklarieren von –Daten für die Operationen –Signatur der Operationen auf den Daten Vorteile: –alle Eigenschaften in einer einzigen Struktur (hier: des Datentyps Warteschlange) –-->: Lokalität der Änderungen Übersichtlichkeit Verständlichkeit
Kap 10: Warteschlange als ADT Vorl EINI-I" Vereinbarung der Warteschlange Problem: –Es fehlt noch der Code für die Operationen. Lösung: –Der Code wird getrennt von der struct -Definition angegeben. In Analogie zu: –Angabe der Signatur der benutzten Funktionen als Funktionsprototypen, davon getrennte Angabe des Codes.
Kap 10: Warteschlange als ADT Vorl EINI-I" Vereinbarung IntListe * Warteschlange :: Init() { DieListe = Kopf = Fuss = NULL; return DieListe; }; Typ des Rückgabewerts Name des Typs Name der Funktion das zum Typ Warteschlange gehörende Init
Kap 10: Warteschlange als ADT Vorl EINI-I" Anmerkungen struct bildet Namensraum: –Die in der struct -Definition definierten Namen (z. B. Kopf, Fuss ) sind hier sichtbar. Bei Definition einer Funktion muß der Name der struct mit angegeben werden, um die Zuordnung zu ermöglichen. –Z.B. kann Init ja auch bei anderen Typen vorkommen.
Kap 10: Warteschlange als ADT Vorl EINI-I" Weitere Beispiele int Warteschlange::DerKopf() { return (DieListe == NULL ? -1 : DieListe->Element); }; void Warteschlange::ListenDruck(ofstream *aus) { IntListe * Laeufer = Kopf; *aus << endl; while (Laeufer != NULL) { *aus Element << " # "; Laeufer = Laeufer->weiter; } *aus << endl; };
Kap 10: Warteschlange als ADT Vorl EINI-I" Weitere Beispiele IntListe * Warteschlange::Entfernen() { if (Kopf == NULL) DieListe = Kopf; else { if (Kopf == Fuss) { Kopf = Fuss = NULL; } else { Kopf = Kopf->weiter; } DieListe = Kopf; } return DieListe; }; Name einer struct Qualifizierungs- zeichen In der struct sichtbare Größen
Kap 10: Warteschlange als ADT Vorl EINI-I" Benutzung der Warteschlange Definition der Warteschlange W Benutzung der Operationen durch qualifizierten Zugriff void main() { ofstream *out = new ofstream("aus.aus"); Warteschlange W; W.Init(); for (int i=1; i < 10; i++) W.Einfuegen(i); W.ListenDruck(out); }
Kap 10: Warteschlange als ADT Vorl EINI-I" IntListe * Warteschlange::Einfuegen(int i){ IntListe *K = new IntListe; K->Element = i; K->weiter = NULL; if (DieListe == NULL){ Kopf = Fuss = K; } else { Fuss->weiter = K; Fuss = K; } DieListe = Kopf; return DieListe; }; Weitere Beispiele iK DieListe Kopf Fuss Kopf Fuss
Kap 10: Warteschlange als ADT Vorl EINI-I" Zugriff über Qualifikation void main() { ofstream *out = new ofstream("aus.aus"); Warteschlange W; W.Init(); for (int i=1; i < 10; i++) W.Einfuegen(i); W.ListenDruck(out); W.Einfuegen(117); *out << "\nNach Einfuegen von 117: " << endl; W.ListenDruck(out); *out << "\nKopf: " << W.DerKopf() << endl; W.Entfernen(); *out<<"\nNach Entfernen des ersten Elements: "<<endl; W.ListenDruck(out); *out << "\nKopf: " << W.DerKopf() << endl; } Definition der Warteschlange
Kap 10: Warteschlange als ADT Vorl EINI-I" # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # Nach Einfuegen von 117: 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 117 # Kopf: 1 Nach Entfernen des ersten Elements: 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 117 # Kopf: 2 Programm Ausgabe
Kap 10: Warteschlange als ADT Vorl EINI-I" Beobachtungen Die "Interna" (hier: Kopf, Fuss, DieListe ) werden "außen" überhaupt nicht benötigt. Diese Interna könnten/sollten privat, d.h. verborgen bleiben Zugriff von außen nur über die entsprechenden Operationen
Kap 10: Warteschlange als ADT Vorl EINI-I" // // 10_1_Warteschlange Version 1 // demonstriert Warteschlangen // #include const int maxLen = 70; struct IntListe { int Element; IntListe * weiter; }; 1
Kap 10: Warteschlange als ADT Vorl EINI-I" struct Warteschlange { IntListe * DieListe; IntListe * Einfuegen(int); IntListe * Entfernen(); IntListe * Init(); int DerKopf(); void ListenDruck(ofstream *); IntListe * Kopf, * Fuss; }; IntListe * Warteschlange::Init() { DieListe = Kopf = Fuss = NULL; return DieListe; }; 2
Kap 10: Warteschlange als ADT Vorl EINI-I" int Warteschlange::DerKopf() { return (DieListe == NULL? -1 : DieListe->Element); }; IntListe * Warteschlange::Einfuegen(int i) { IntListe * K = new IntListe; K->Element = i; K->weiter = NULL; if (DieListe == NULL){ Kopf = Fuss = K;} else { Fuss->weiter = K; Fuss = K;} DieListe = Kopf; return DieListe; }; 3
Kap 10: Warteschlange als ADT Vorl EINI-I" IntListe * Warteschlange::Entfernen() { if (Kopf == NULL){ DieListe = NULL; return NULL;} else { if (Kopf == Fuss) { Kopf = Fuss = NULL;} else { Kopf = Kopf->weiter;} DieListe = Kopf; return DieListe;} }; void Warteschlange::ListenDruck(ofstream *aus) { IntListe * Laeufer = Kopf; *aus << endl; while (Laeufer != NULL) { *aus Element << " # "; Laeufer = Laeufer->weiter;} *aus << endl; };// 4
Kap 10: Warteschlange als ADT Vorl EINI-I" int main() { ofstream *out = new ofstream("aus.aus"); Warteschlange W; W.Init(); for (int i=1; i < 10; i++) W.Einfuegen(i); W.ListenDruck(out); W.Einfuegen(117); *out << "\nNach Einfuegen von 117: " << endl; W.ListenDruck(out); *out << "\nKopf: " << W.DerKopf() << endl; W.Entfernen(); *out << "\nNach Entfernen des ersten Elements:" << endl; W.ListenDruck(out); *out << "\nKopf: " << W.DerKopf() << endl; return 0; }// 5
Kap 10: Warteschlange als ADT Vorl EINI-I" Abstrakter Datentyp Warteschlange als eine Art Datenkapsel mit – internem Zustand ( Kopf, Fuss, DieListe ) – Zugriffsoperationen ( Einfuegen etc.) – Zustand von außen nur über Zugriffsfunktionen änderbar, nicht direkt!
Kap 10: Warteschlange als ADT Vorl EINI-I" innerer Zustand (verborgen) Zugriff und Änderung nur durch wohldefinierte Operationen
Kap 10: Warteschlange als ADT Vorl EINI-I" Operationen auf Warteschlangen DieListe KopfFuss Einfuegen(int) Entfernen() Init() DerKopf() ListenDruck(...) privat öffentlich
Kap 10: Warteschlange als ADT Vorl EINI-I" Neudeklaration struct Warteschlange { private: IntListe * DieListe; IntListe * Kopf, * Fuss; public: void Einfuegen(int); void Entfernen(); void Init(); int DerKopf(); void ListenDruck(ofstream *); }; neu beachte: void Programm
Kap 10: Warteschlange als ADT Vorl EINI-I" Anmerkungen public –bewirkt, daß auf die darauf folgenden Namen von außen zugegriffen werden darf; dies geschieht durch Qualifikation. private –bewirkt, daß die darauf folgenden Namen vor dem expliziten Zugriff von außen (durch Qualifikation) geschützt sind.
Kap 10: Warteschlange als ADT Vorl EINI-I" Beispiel Warteschlange W sei definiert Legal sind z.B.: –W.Init() –W.Einfuegen(45) –W.DerKopf() Illegal sind z.B.: - W.Kopf - W.DieListe - W.Fuss
Kap 10: Warteschlange als ADT Vorl EINI-I" Ein Rückgabewert impliziert die Weitergabe von interner Strukturinformation nach außen. Dies kann unerwünscht sein. --> Datenkapselung. Wieso void?
Kap 10: Warteschlange als ADT Vorl EINI-I" void Warteschlange::Einfuegen(int i) { IntListe *K = new IntListe; K->Element = i; K->weiter = NULL; if (DieListe == NULL){ Kopf = Fuss = K; } else { Fuss->weiter = K; Fuss = K; } DieListe = Kopf; }; Änderungen: Typ der Rückgabe wird void ; return eliminiert Änderungen: Typ der Rückgabe wird void ; return eliminiert IntListe * Warteschlange::Einfuegen(int i){ IntListe *K = new IntListe; K->Element = i; K->weiter = NULL; if (DieListe == NULL){ Kopf = Fuss = K; } else { Fuss->weiter = K; Fuss = K; } DieListe = Kopf; return DieListe; };
Kap 10: Warteschlange als ADT Vorl EINI-I" Anmerkung: Trick Kopf ist als privat deklariert –auf Kopf kann also von außen nicht zugegriffen werden, –kann also Kopf weder lesen noch von außen verändern. Trick: definiere eine öffentliche Zugriffsfunktion DerKopf () –damit kann ich den Wert von Kopf lesen –analog: schreiben.
Kap 10: Warteschlange als ADT Vorl EINI-I" Warteschlange als abstrakter Datentyp Warteschlange wurde hier als abstrakter Datentyp (ADT) definiert. ADTs sind charakterisiert durch – Offenlegen der Schnittstellen (Signaturen) – Verbergen der Implementation (d.h. Zugriff nur über wohldefinierte Operationen) Wichtige Konstruktion in der Softwaretechnik, insb. im objektorientierten Entwurf. Wichtig im nächsten Semester.
Kap 10: Warteschlange als ADT Vorl EINI-I" // // 10_2_Warteschlange_2 // demonstriert Warteschlangen // mit private/public Komponenten // #include const int maxLen = 70; struct IntListe { int Element; IntListe * weiter; }; // 1
Kap 10: Warteschlange als ADT Vorl EINI-I" struct Warteschlange { private: IntListe * DieListe; IntListe * Kopf, * Fuss; public: void Einfuegen(int); void Entfernen(); void Init(); int DerKopf(); void ListenDruck(ofstream *); }; void Warteschlange::Init() { DieListe = Kopf = Fuss = NULL; }; int Warteschlange::DerKopf() { return (DieListe == NULL? -1 :DieListe->Element); };// 2
Kap 10: Warteschlange als ADT Vorl EINI-I" void Warteschlange::Einfuegen(int i) { IntListe *K = new IntListe; K->Element = i; K->weiter = NULL; if (DieListe == NULL){ Kopf = Fuss = K; } else { Fuss->weiter = K; Fuss = K; } DieListe = Kopf;}; // 3
Kap 10: Warteschlange als ADT Vorl EINI-I" void Warteschlange::Entfernen() { if (Kopf == NULL){ DieListe = NULL;} else { if (Kopf == Fuss) { Kopf = Fuss = NULL;} else { Kopf = Kopf->weiter;} DieListe = Kopf;}}; void Warteschlange::ListenDruck(ofstream *aus) { IntListe * Laeufer = Kopf; *aus << endl; while (Laeufer != NULL) { *aus Element << " # "; Laeufer = Laeufer->weiter; } *aus << endl; };// 4
Kap 10: Warteschlange als ADT Vorl EINI-I" int main() { ofstream *out = new ofstream("aus.aus.neu"); Warteschlange W; W.Init(); for (int i=1; i < 10; i++) W.Einfuegen(i); W.ListenDruck(out); W.Einfuegen(117); *out << "\nNach Einfuegen von 117: " << endl; W.ListenDruck(out); *out << "\nKopf: " << W.DerKopf() << endl; W.Entfernen(); *out << "\nNach Entfernen des ersten Elements: " << endl; W.ListenDruck(out); *out << "\nKopf: " << W.DerKopf() << endl; return 0; } // 5
Kap 10: Warteschlange als ADT Vorl EINI-I" Zurück zur Breitensuche Strategie –Verwendung einer Warteschlange Q, die aus Knoten des Baums besteht, –Füge zunächst den Wurzelknoten in Q ein, der Kopf K von Q wird gedruckt. nach dem Druck: –ist K.LSohn != NULL, so wird dieser Knoten in Q eingefügt, –ist K.RSohn != NULL, so wird dieser Knoten in Q eingefügt, das geschieht solange, bis Q leer ist
Kap 10: Warteschlange als ADT Vorl EINI-I" Änderung im Typ des Listen- elements Anpassung der Datentypen struct BinBaum { char text[maxLen]; int zaehler; BinBaum * LSohn, *RSohn; }; struct BaumListe { BinBaum * Element; BaumListe * weiter; }; struct Warteschlange { private: BaumListe * DieListe; BaumListe * Kopf, * Fuss; public: void Einfuegen(BinBaum *); void Entfernen(); void Init(); int IstLeer(); BinBaum * DerKopf(); };
Kap 10: Warteschlange als ADT Vorl EINI-I" Zentrale Prozedur void KnotenDruck(BinBaum *, ofstream *); void BreitenSuche(BinBaum *K, ofstream *aus) { Warteschlange W; W.Init(); W.Einfuegen(K); while (!W.IstLeer()) { BinBaum *L = W.DerKopf(); W.Entfernen(); W.Einfuegen(L->LSohn); W.Einfuegen(L->RSohn); KnotenDruck(L, aus); } } Programm:
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche // demonstriert Breitensuche in einem // binaeren Suchbaum. // #include const int maxLen = 70; struct BinBaum { char text[maxLen]; int zaehler; BinBaum * LSohn, *RSohn; }; struct BaumListe { BinBaum * Element; BaumListe * weiter; };// 1
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. struct Warteschlange { private: BaumListe * DieListe; BaumListe * Kopf, * Fuss; public: void Einfuegen(BinBaum *); void Entfernen(); void Init(); bool IstLeer(); BinBaum * DerKopf(); }; BinBaum * Einlesen(ifstream *); // Funktionsprototypen void BreitenSuche(BinBaum *, ofstream *); void InOrder(BinBaum *, ofstream *); BinBaum * Einfuegen(BinBaum *, char *); void KnotenDruck(BinBaum *, ofstream *); void Schreiben(char *, int, ofstream *); // 2
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. void Warteschlange::Init() { DieListe = Kopf = Fuss = NULL; } BinBaum * Warteschlange::DerKopf() { return (DieListe == NULL? NULL : DieListe->Element);} void Warteschlange::Einfuegen(BinBaum * B) { if (B != NULL) { BaumListe *K = new BaumListe; K->Element = B; K->weiter = NULL; if (DieListe == NULL) Kopf = Fuss = K; else { Fuss->weiter = K; Fuss = K;} DieListe = Kopf;}}// 3
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. void Warteschlange::Entfernen() { if (Kopf == NULL){ DieListe = NULL; } else { Kopf = Kopf->weiter; } DieListe = Kopf; } bool Warteschlange::IstLeer() { return (DieListe == NULL? true: false); } // 4
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. main() { BinBaum * BST; ifstream *EingabeDatei; ofstream *BreitAusgabeDatei = new ofstream("breit.doc"); ofstream *TiefAusgabeDatei = new ofstream("tief.doc"); EingabeDatei = new ifstream("Beweis.txt"); BST = Einlesen(EingabeDatei); InOrder(BST, TiefAusgabeDatei); BreitenSuche(BST, BreitAusgabeDatei); } // 5
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. BinBaum * Einlesen(ifstream *inp) { BinBaum *bst = NULL; char gelesen[maxLen]; *inp >> gelesen; while (!(*inp).eof()) { bst = Einfuegen(bst, gelesen); *inp >> gelesen; } return bst; } // 6
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. BinBaum * Einfuegen(BinBaum *B, char * k) { if (B == NULL) { BinBaum *Hilf = new BinBaum; strcpy(Hilf->text, k); Hilf->zaehler = 1; Hilf->LSohn = Hilf->RSohn = NULL; B = Hilf;} else { int Vergl = strcmp(B->text,k); if (Vergl < 0) B->RSohn = Einfuegen(B->RSohn, k); else if (Vergl > 0) B->LSohn = Einfuegen(B->LSohn, k); else if (Vergl == 0) B->zaehler += 1;} return B;}// 7
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. void BreitenSuche(BinBaum *K, ofstream *aus) { // void KnotenDruck(BinBaum *, ofstream *); Warteschlange W; W.Init(); W.Einfuegen(K); while (!W.IstLeer()) { BinBaum *L = W.DerKopf(); W.Entfernen(); W.Einfuegen(L->LSohn); W.Einfuegen(L->RSohn); KnotenDruck(L, aus); } // 8
Kap 10: Warteschlange als ADT Vorl EINI-I" // 10_3_Breitensuche Forts. void InOrder(BinBaum *K, ofstream *aus) { if (K != NULL) { InOrder(K->LSohn, aus); KnotenDruck(K, aus); InOrder(K->RSohn, aus); } void KnotenDruck(BinBaum *T, ofstream *aus){ Schreiben(T->text, T->zaehler, aus); } void Schreiben(char * s, int k, ofstream *aus) { *aus << k << "\t\t\t" << s << endl; } // 9
Kap 10: Warteschlange als ADT Vorl EINI-I" Suche in WWW-Seiten. K1 K1.1 K1.2 K1.3 K1.1.1 K1.1.2 K1.1.3 usw. Weitere Anwendung: WWW-Seite enthält eingebettete Links. Annahme: in Kapiteln organisiertes "Buch".
Kap 10: Warteschlange als ADT Vorl EINI-I" Hierarchische Struktur Breitensuche: liest erst alle Kapitelköpfe, bevor die einzelnen Unterkapitel gelesen werden (z.B. Überblick) Tiefensuche: geht in die Tiefe, z. B. gezieltere Suche ETC. K1 K1.1K1.2 K1.1.1K1.1.2K1.1.3