Induktive Datenbereiche Induktive Datenbereiche, Verkettete Listen, Mutatoren, Operationen, Konstruktoren, Prädikate, Selektoren, Bäume, Binärbäume, Bäume mit Blättern, abstrakte Klassen Induktiv definierte Daten Die natürlichen Zahlen sind induktiv definiert 0 ist eine natürliche Zahl Wenn N eine natürliche Zahl ist, dann auch N+1 Binärzahlen kann man induktiv definieren 0 ist eine Binärzahl 1 ist eine Binärzahl Ist B eine Binärzahl, dann auch B0, und B1. Strings kann man induktiv definieren Der leere String “ “ ist ein String Ist S ein String und z ein Zeichen, dann ist S . z ein String Ausdrücke wurden bereits induktiv definiert Binärbäume kann man induktiv definieren 0, |, ||, |||, ||||, |||||, ||||||, ... Der leere Baum ist ein Binärbaum Sind B1 und B2 Binärbäume, dann auch Praktische Informatik I 0, 1, 00, 01, 10, 11, 000, 001, 010, 011, 100, 101, 110, 111 ““, “a“, “b“, ... “aa“, “ab“, ... , “ba“, “bb“, ... “aaa“, “aab“, ... B1 B2 H. Peter Gumm, Philipps-Universität Marburg Verkettete Listen Listen sind Folgen von Elementen Im Unterschied zu Arrays können Listen beliebig wachsen und schrumpfen Verkettete Listen kann man sich wie eine Perlenschnur vorstellen Neue Elemente werden an die Liste angehängt Nicht mehr benötigte Elemente können entfernt werden Von jeder Perle gibt es eine Verbindung zur folgenden In den Perlen befindet sich die Information Die Liste besteht aus Zellen. Jede Zelle hat einen Inhalt, und Einen Verweis auf die folgende Zelle Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Die Zelle – unsere Perle Die Liste besteht aus Zellen. Jede Zelle hat einen Inhalt, und einen Verweis auf die folgende Zelle 17 inhalt next Praktische Informatik I 42 inhalt next 101 38 inhalt next inhalt next H. Peter Gumm, Philipps-Universität Marburg Listen: Perlen aufgefädelt Ein Liste besteht aus einem Link auf die erste Zelle Methoden um Elemente aufzunehmen zu suchen zu löschen, etc. anfang vorher nachher 42 inhalt next neue Zelle Praktische Informatik I nachher 101 38 inhalt next inhalt next H. Peter Gumm, Philipps-Universität Marburg Wir bauen uns eine Liste in BlueJ BlueJ zeigt durch einen gestrichelten Pfeil an, dass Liste die Klasse Zelle benutzt. wir erzeugen eine Liste meineListe und speichern nacheinander 37 42 81 Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Wir inspizieren die Liste uiu Dies entspricht 81 anfang Praktische Informatik I inhalt next 42 inhalt next 37 inhalt next H. Peter Gumm, Philipps-Universität Marburg Entfernen eines Elementes Um ein Element einer Liste zu entfernen, verbinden wir die Vorgängerzelle mit der Nachfolgerzelle 81 anfang inhalt next 37 42 inhalt next inhalt next Zelle v v.next = v.next.next Das abgeklemmte Element wird irgendwann automatisch von der Java-Speicherbereinigung (garbage collection) gefunden und recycled. Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg removeNth – entferne n-tes Element Von der leeren Liste kann man nichts entfernen Das erste Element hat keine Vorgängerzelle, daher müssen wir es gesondert behandeln Solange Zähler n > 1, und v einen Nachfolger hat vermindere n und rücke v eine Zelle weiter. Falls v einen Nachfolger hat, klemme ihn ab. Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Mutatoren, Operationen Für FürMethoden Methodenzur zurManipulation Manipulationvon von Daten Datengibt gibtes eszwei zweiMöglichkeiten Möglichkeiten insert ist ein Mutator removeNth ist ein Mutator 1. 1. Die DieMethode Methodeverändert verändertdas dasObjekt Objekt Solche SolcheMethoden Methodenheißen heißenMutatoren Mutatoren Mutatoren sind Kennzeichen Mutatoren sind Kennzeichendes des imperativen Programmierens imperativen Programmierens •• void voidMethoden Methodensind sindimmer immerMutatoren Mutatoren •• Mutatoren Mutatorensind sindmanchmal manchmaleffizienter effizienter •• •• 2. 2. Die DieMethode Methodelässt lässtdas dasObjekt Objekt unverändert. Resultat ist unverändert. Resultat istneues neuesObjekt Objekt •• •• •• •• Praktische Informatik I Solche SolcheMethoden Methodenheißen heißenOperationen Operationen Operationen Operationensind sindKennzeichen Kennzeichendes des deklarativen Programmierens deklarativen Programmierens Mit MitOperationen Operationenkann kannman manleichter leichter umgehen umgehen Operationen Operationensind sindweniger wenigerfehleranfällig fehleranfällig Eine insert entsprechende Operation müsste eine neue Liste konstruieren und die alte unversehrt lassen Eine removeNth entsprechender Operation müsste eine neue Liste konstruieren die alte unversehrt lassen Wie soll das gehen ? Das soll einfacher sein ? H. Peter Gumm, Philipps-Universität Marburg Programmieren mit Operationen Konstruktoren Konstruiert die leere Liste (anfang = null) Konstruiert eine neue Liste mit erstem Element n und Restliste l neue Liste neue Zelle anfang alte Liste l Praktische Informatik I 81 anfang 17 42 37 37 H. Peter Gumm, Philipps-Universität Marburg Notwendige Operationen Im Falle der Listen: Konstruktoren Konstruktoren, , bauen Elemente des Datentyp bauen Elemente des Datentyp Meist gibt es mehrere Konstruktoren Meist gibt es mehrere Konstruktoren bestimmten bestimmtenKonstruktor Konstruktoraufgebaut aufgebautwurde wurde Hier: ob eine Liste Hier: ob eine Liste leer leeroder odernichtleer nichtleeristist Eine Liste ist leer, oder nicht leer, dh. erzeugt durch Liste() oder durch Liste(int, Liste) Prädikate Prädikate Testen, ob ein Datenobjekt mit einem Testen, ob ein Datenobjekt mit einem Selektoren Selektoren Liefern die Bestandteile, aus der das Liefern die Bestandteile, aus der das Datenobjekt Datenobjektaufgebaut aufgebautwurde wurde Selektoren gehen davon aus, dass das Selektoren gehen davon aus, dass das Datenobjekt mit bestimmten Datenobjektgebaut miteinem einem bestimmten Konstruktor wurde Konstruktor gebaut wurde Listenkonstruktoren Listenprädikat Selektoren Falls die Liste leer ist, hat sie keinen Bestandteil, braucht also keinen Selektor Ansonsten besteht sie aus den Bestandteilen. head() - Kopf, erstes Element tail() - Liste der restlichen Elemente Praktische Informatik I istLeer() testet, ob eine Liste leer ist H. Peter Gumm, Philipps-Universität Marburg Implementierung: Prädikat, Selektoren Praktische Informatik I Prädikate sind immer Boolesche Operationen Die folgenden Selektoren sind nur anwendbar, falls istLeer() == false. head : Kopf der Liste tail : Rest der Liste H. Peter Gumm, Philipps-Universität Marburg Indexkarte für Listen Beliebige Listenoperationen können sich auf diesen Methoden abstützen: Liste Konstruktoren: Liste() Liste(int,Liste) Methoden: boolean istLeer() int head() Liste tail(Liste) Wir verstecken alle anderen Felder und Methoden hinter dem Schlüsselwort: private Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Kochrezept für Listenoperationen llwerden werdenrekursiv rekursivdefiniert definiert meineMethode(){ meineMethode(){ if(l.istLeer()) if(l.istLeer()) {{ .. .. Trivialfall Trivialfall ...} ...} else { else { Methoden Methodenfür füreine eineListe Liste Kombiniere KombiniereResultat Resultataus aus l.head() l.head() und und l.tail().meineMethode() l.tail().meineMethode() }} Eine Liste ist tail() Für den Test haben wir das Prädikat head() und einer Rest-(Liste) istLeer Für den Zugriff auf die Bestandteile haben wir die Selektoren Praktische Informatik I leer, oder sie hat einen Kopf head tail H. Peter Gumm, Philipps-Universität Marburg Einfache Listenoperationen Eine Liste istLeer() oder besteht aus Element head() und RestListe tail() Methoden werden rekursiv definiert Basisfall: leere Liste Methoden werden rekursiv definiert Rekursiver Fall: Basisfall: leere Liste Meist trivial Meist trivial Zur Verfügung stehen: head() tail().methode() Rekursiver Fall: Zur Verfügung stehen: head() tail().methode() Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg withoutNth als Operation withoutNth Eine Operation Ergebnis: Wie Ausgangsliste ohne n-tes Element Ursprüngliche Liste bleibt unverändert neue Zelle 81 tail() anfang inhalt next meineListe 81 anfang Praktische Informatik I inhalt next 42 inhalt next 37 inhalt next 14 inhalt next H. Peter Gumm, Philipps-Universität Marburg Bäume – 2-dimensionale Listen Bäume sind hierarchische Strukturen Bäume bestehen aus Knoten und Teilbäumen Bei Binärbäumen hat jeder Knoten zwei Unterbäume, Wurzelknoten den linken Unterbaum den rechten Unterbaum In den Knoten kann Information gespeichert werden Praktische Informatik I Rechter Teilbaum Linker Teilbaum H. Peter Gumm, Philipps-Universität Marburg Baumknoten class Knoten{ Knoten left; char content; Knoten right; } Wir implementieren einen Knoten als Zelle mit zwei Zeigern. Zur Abwechslung speichern wir Zeichen in den Knoten ‘+‘ left inhalt right ‘x‘ left Praktische Informatik I inhalt right ‘2‘ left inhalt right H. Peter Gumm, Philipps-Universität Marburg BinTree Die Klasse Knoten ist nur eine Hilfsklasse für die Klasse BinTree Wir implementieren sie daher als innere Klasse (geschachtelt in BinTree). class BinTree{ Knoten wurzel; private class Knoten{ Knoten left; char content; Knoten right; // Konstruktor Knoten(Knoten b1, char c, Knoten b2){ left = b1; content = c; right = b2; } } } Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Konstruktoren, Prädikate, Selektoren Konstruktoren Konstruktoren BinTree() BinTree() BinTree ( B1, c, B2) Der Derleere leereBaum Baum c BinTree( BinTree(BB11, ,c,c,BB22)) neuer neuerBinTree BinTreemit mit linkem linkemTeilbaum TeilbaumBB1 1 rechtem rechtemTeilbaum TeilbaumBB2 2 Inhalt Inhaltder derWurzel: Wurzel:cc Prädikat Prädikat isEmpty isEmpty Testet, Testet,ob obein einBinTree BinTreeleer leerist, ist,oder odereinen einen rechten rechtenund undlinken linkenTeilbaum Teilbaumenthält enthält B2 B1 Selektoren Selektorenleft, left,right, right,content content Falls Fallsder derBinTree BinTreenicht nichtleer leerist, ist,liefert liefert left() den linken Teilbaum left() den linken Teilbaum right() den rechten Teilbaum right() den rechten Teilbaum content() den Inhalt der Wurzel content() den Inhalt der Wurzel Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Implementierung class class BinTree{ BinTree{ private private Knoten Knoten wurzel; wurzel; // // Konstruktoren Konstruktoren BinTree(){}; BinTree(){}; Implementierung verläuft analog zu Listen // // der der leere leere Baum Baum BinTree(BinTree BinTree(BinTree b1, b1, char char c, c, BinTree BinTree b2){ b2){ wurzel = new Knoten(b1.wurzel,c,b2.wurzel); wurzel = new Knoten(b1.wurzel,c,b2.wurzel); }} // // Prädikat Prädikat boolean boolean isEmpty(){ isEmpty(){ return return wurzel==null; wurzel==null; }} // // Selektoren Selektoren BinTree BinTree left(){ left(){ BinTree BinTree ll == new new BinTree(); BinTree(); l.wurzel l.wurzel == this.wurzel.left; this.wurzel.left; return l; return l; }} //this //this nicht nicht nötig nötig char char content(){ content(){ return return this.wurzel.content; this.wurzel.content; }} Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Indexkarte für BinTree Beliebige BinTree-Operationen können sich auf diesen Methoden abstützen: BinTree Konstruktoren: BinTree() BinTree(BinTree,char,BinTree) Methoden: boolean isEmpty() BinTree left() char content() BinTree right() Wir verstecken alle anderen Felder und Methoden hinter dem Schlüsselwort private Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Rekursion auf Binärbäumen Binärbäume sind induktiv definiert BinTree ( B1, s, B2) Der leere Baum ist ein Binärbaum Sind B1 und B2 Binärbäume und s ein String, dann ist der Baum mit Wurzel s, linkem Teilbaum B1 und rechtem Teilbaum B2 ein Binärbaum * Operationen f auf Binärbäumen sind rekursiv - + 5 * x Beispiel: tiefe (engl.: depth) Falls isEmpty(B): gib f(B) direkt an Ansonsten beschreibe wie sich der Wert von f aus f(B1), f(B2) und s ergibt. Falls isEmpty(B) : 0 Ansonsten max( left().depth(), right.depth() ) + 1 Beispiel: exists(char c) (ist c vorhanden ?) Falls isEmpty(B) : false Ansonsten: left().exists(c) || content()== c || right().exists(c) Praktische Informatik I 3 y depth: 4 Dieser Baum repräsentiert (x+3*y)*(-5) H. Peter Gumm, Philipps-Universität Marburg Einfache Baumoperationen class XBinTree extends BinTree{ int depth(){ if(isEmpty()) return 0; else return max( ((XBinTree)left()).depth() ((XBinTree)right()).depth()) +1; } boolean exists(char c){ if(isEmpty()) return false; else return ((XBinTree)left()).exists(c) || content()==c || ((XBinTree)right()).exists(c); } isEmpty(), left(), right() werden aus der Oberklasse geerbt. left() liefert einen BinTree() depth() ist nur in der Unterklasse definiert – für XBinTrees Wir brauchen casts um die BinTrees in XBinTrees zu verwandeln Hilfsmethode max ist nicht an ein Objekt gebunden. Wir erklären sie als Klassenmethode, also static. Das sie nur hier gebraucht wird, verstecken wir sie mit private. private static int max(int x, int y) { return (x < y)? y : x; } Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Bäume mit Blättern Jeder Zweig soll in einem Blatt enden Die Information speichern wir in den Blättern “Paul“ “Anna“ “Eva“ Jeder Knoten hat zwei Unterbäume class Knoten{ “Peter“ “Otto“ class Blatt{ Knoten links; Knoten rechts; String info; } } Wir haben ein Problem: Wir müssen auch zulassen : Blatt links; Blatt rechts; Praktische Informatik I ... aber ein Blatt ist kein Knoten ! H. Peter Gumm, Philipps-Universität Marburg Wie kann man Klassen vereinigen ? Wir wollen Blatt und Knoten zu einer Klasse Baum zusammenfassen. Blatt wird Unterklasse von Baum Knoten wird Unterklasse von Baum class Blatt extends Baum class Knoten extends Baum Viele Methoden müssen für alle Bäume funktionieren istBlatt() istKnoten depth() draw() Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Default-Methoden redefinieren In Baum definieren wir die Methoden irgendwie: boolean isBlatt(){ return false; // äähm na ja ... } void draw(){ } // tu nix In den Unterklassen redefinieren wir sie wieder // z.B. in Blatt: boolean isBlatt { return true; } void draw( System.out.println(info); } Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg besser: Abstrakte Klassen Vereinigung von Unterklassen Gemeinsame Methoden In der Oberklasse abstrakt erklärt class Knoten “Pete“ “Eva“ In jeder nicht abstrakten Unterklasse implementiert Jedes Blatt ist ein Baum Jeder Knoten ist ein Baum Definiere Baum als abstrakte Klasse, die Blatt und Knoten umfasst Praktische Informatik I class Blatt “Ann“ Nur die Signatur wird aufgeführt Beispiel abstract class Baum “Jon“ “Paul“ Abstrakte Methoden istKnoten draw istBlatt depth …etc. … H. Peter Gumm, Philipps-Universität Marburg Abstrakte Klasse Baum Klassen werden wechselseitig rekursiv abstract class Baum{ … } Jeder Knoten ist ein Baum “Eva“ “Ann“ “Pete“ class Knoten extends Baum{ Baum links; Baum rechts; … } Jedes Blatt ist ein Baum Praktische Informatik I class Blatt extends Baum{ String info; } “Eva“ “Jon“ “Paul“ H. Peter Gumm, Philipps-Universität Marburg Implementierung abstract class Baum{ Abstrakte Methoden müssen in (konkreten) Unterklassen implementiert werden Wird vom Compiler geprüft class Knoten extends Baum{ Baum links, rechts; abstract boolean istBlatt(); abstract int depth(); … } class Blatt extends Baum{ String info; boolean istBlatt(){ return false;} int depth(){ return 1+max(links.depth(), rechts.depth()); } boolean istBlatt(){ return true;} int depth(){ return 0; } … } } Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Operationen auf rekursiven Daten Funktionen auf induktiv definierten Daten sind rekursiv am einfachsten Beispiel : draw() Hilfsfunktion draw(int n) Malt einen Baum ab Spalte n Rote Verbindungslinien nur zur weiteren Hervorhebung In Blatt: println(info); In Knoten: links.draw(n+2); println(„+“); rechts.println(n+2); Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Abstrakte Klassen haben keine eigenen Objekte Was sollte auch new Baum() liefern: ein Blatt oder einen Knoten ? können abstrakte und konkrete Methoden enthalten abstract boolean istBlatt(); boolean istKnoten(){ return !istBlatt(); } Sobald eine Methode abstrakt ist, muss die ganze Klasse abstrakt erklärt werden Der Compiler achtet darauf, dass jede abstrakte Methode in jeder Unterklasse implementiert wird. Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Listen als abstrakte Klassen Listen sind leer oder nicht leer Nichtleere Listen haben head und tail Die leere Liste hat kein Feld Traditionell heißt der Konstruktor einer nichtleeren Liste Cons Die leere Liste nennt man Nil Wir definieren Liste als abstrakte Klasse, Cons und Nil als (konkrete) Unterklassen Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Die abstrakte Klasse List abstract abstract class class List{ List{ abstract abstract boolean boolean istLeer(); istLeer(); abstract abstract int int length(); length(); // // Prüft, Prüft, ob ob nn in in der der Liste Liste vorkommt vorkommt abstract boolean exists(int n); abstract boolean exists(int n); //Hängt //Hängt ll vorne vorne an an die die Liste Liste an an abstract List prepend(List l); abstract List prepend(List l); //Hängt //Hängt ll hinten hinten an an die die Liste Liste an an abstract List append(List l); abstract List append(List l); //Darstellung //Darstellung im im Terminal Terminal Fenster Fenster abstract void draw(); abstract void draw(); }} abstract abstract void void niceDraw(); niceDraw(); Auch eine List - im alten Griechenland Praktische Informatik I H. Peter Gumm, Philipps-Universität Marburg Cons und Nil class class Cons Cons extends extends List{ List{ int content; int content; List List next; next; class class Nil Nil extends extends List{ List{ // // keine keine Felder Felder // // Konstruktor Konstruktor Cons(int Cons(int inhalt, inhalt, List List rest){ rest){ content = inhalt; next content = inhalt; next == rest;} rest;} // // Konstruktor Konstruktor Nil(){}; Nil(){}; //Prädikat //Prädikat boolean boolean istLeer(){return istLeer(){return false;} false;} // // Prädikat Prädikat boolean boolean istLeer(){return istLeer(){return true;} true;} // // Selektoren Selektoren int int head(){ head(){ return return content; content; }} // // Selektoren: Selektoren: // keine, // keine, da da keine keine Bestandteile Bestandteile List List tail(){ tail(){ return return next; next; }} // // Luxus Luxus (optionale (optionale Funktionen) Funktionen) int length(){ int length(){ return return 1+tail().length(); 1+tail().length(); }} ... ... }} Praktische Informatik I // // Luxus Luxus (optionale (optionale Funktionen) Funktionen) int length(){ int length(){ return return 0; 0; }} ... ... }} H. Peter Gumm, Philipps-Universität Marburg