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