Diskrete Mathe 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Diskrete Mathematik I Listen Vorlesung 4
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Diskrete Mathematik I
Listen
Vorlesung 4
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
• letzte Stunde:rekursive Definitionen und Methoden
• heute:rekursive Datenstrukuren: Listen
Rekursion
1
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 192
• Listen – ... als rekursive Struktur– ... als dynamische Datenstrukturen
• Die Klasse Element– ... mit Element-konstruktor
• Eine richtige kleine Liste• Ein UML-Diagramm für „Element“• Aber wie kommt man nun zu einer Liste?• Anfügen von Elementen - Beispiel
Übersicht I
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 193
• Einfügen am Anfang einer Liste– Problem– Beispiel– Problem der bisherigen Lösung
• Die Klasse „Liste“ (UML-Diagramm)• Die Klasse Element (vollständig)• Die Klasse „Liste“
Übersicht II
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 194
• Die leere Liste Null ist eine Liste. • Wenn E ein Element ist und L eine Liste, dann ist
E · L eine Liste.• Beispiele:
– die leere Liste { }– {1}– {1,3,2,5}
• Graphik für die leere Liste:
Listen als rekursive Struktur
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 195
• flexible Datenstruktur ohne vorherige Festlegung auf die Größe
• Vorteile gegenüber Arrays– beliebige Größenänderungen– effiziente Umordnung der Elemente
• Nachteil gegenüber Arrays– kein direkter Zugriff auf einzelne Elemente
Listen als Dynamische Datenstrukturen
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 196
class Element{ int wert; Element weiter;}
Die Klasse Element
5
Element
Zeiger auf ein Element
int
A 4x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 197
... mit Element-konstruktor
Das ist neu
• Die Methode Element(int i) ist ein Konstruktor, der bei der Erzeugung eines Elements mit new Element(i) automatisch aufgerufen wird.
class Element { Element(int i) { wert = i; weiter = null;}
int wert; Element weiter;
}
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 198
A 7x
Eine richtige kleine Liste
5
Die leere Liste
3 7
Der Kopf der Liste
Der Rest der Liste
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Beachte:• „weiter“ ist kein Attribut, sondern eine Beziehung• eine (UML-) Beziehung wird (in Java) als Attribut einer zugehörigen Klasse
implementiert• eine UML-Beziehung kann auch rekursiv sein
9
A 13x
Ein UML-Diagramm für „Element“
weiter
0..1
Beziehung Konstruktor
Ein oderkein Nachfolger
0..1
Element
+Element(i : int)
-wert : int
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1910
• Wir haben:– die Klasse Element
• Eine Liste entsteht durch Erzeugung und Verkettung von Objekten vom Typ Element– Erzeugen des ersten Elements
• mit dem Konstruktor „Element“– Anfügen eines Elements
• zusätzliche Prozedur
Aber wie kommt man nun zu einer Liste?
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1911
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Anfügen von Elementen
Sucht das letzte Element
Zeiger auf das aufrufende Objekt
fügt neues Element an
A 10x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
KopfElement kopf;
class Element{ Element(int i) { wert = i; weiter = null; } int wert; Element weiter;}
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);
class Element{ Element(int i) { wert = i; weiter = null; } int wert; Element weiter;}
Kopf
12
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);
class Element{ Element(int i) { wert = i; weiter = null; } int wert; Element weiter;}
25
Kopf
12
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);kopf.FügeAn(22);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
25
Kopf
12
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);kopf.FügeAn(22);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
lauf25
Kopf
12
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);kopf.FügeAn(22);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
25 22
12
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);kopf.FügeAn(22);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
25
22
12
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
22
25
Element kopf;kopf = new Element(25);kopf.FügeAn(22);kopf.FügeAn(28);
12
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Element kopf;kopf = new Element(25);kopf.FügeAn(22);kopf.FügeAn(28);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
22
25 lauf
1212
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Element kopf;kopf = new Element(25);kopf.FügeAn(22);kopf.FügeAn(28);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
25
lauf
22
1212
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);kopf.FügeAn(22);kopf.FügeAn(28);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
25
lauf
22
1212
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Element kopf;kopf = new Element(25);kopf.FügeAn(22);kopf.FügeAn(28);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
25
22
28
lauf
1212
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Element kopf;kopf = new Element(25);kopf.FügeAn(22);kopf.FügeAn(28);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
25
22
28
1212
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1912
Element kopf;kopf = new Element(25);kopf.FügeAn(22);kopf.FügeAn(28);
void FügeAn(int neuerWert){ Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert);}
Kopf
25
22
28
1212
A 25x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
• Problem: es gibt bislang nur die Klasse Element• die Operation Einfügen muß vom ersten Element aufgerufen
werden• Umsetzung der Referenz „kopf“ erforderlich• das Kopf-Element hat aber keinen Zugriff auf die Referenz „kopf“• Lösung: Umkopieren von Wert
13
A 8x
Problem: Einfügen am Anfang einer Liste
15 22 28
15 22 2817
kopf
kopf
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1914
void FügeEin(int neuerWert){ Element neuesElement = new Element(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
Kopf 25 22 28
kopf.FügeEin(17)
A 9x
1515
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1915
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
Kopf 25 22 28
neuesElement 25
15
A 9x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1915
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
neuesElement 25
Kopf 25 22 28
15
A 9x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1915
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
Kopf 25 22 28
25
15
A 9x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1915
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
25 22 28Kopf
25
15
A 9x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1915
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
25 22 28Kopf 25
15
A 9x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1915
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
17 22 28Kopf 25
15
A 9x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1915
void FügeEin(int neuerWert){ Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert;}
Einfügen am Anfang einer Liste
16
17 22 28Kopf 25
15
A 9x
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1916
• Einfügen am Anfang mehr als umständlich• Einfügen am Ende ineffizient, insbesondere wenn die Liste sehr lang ist• wo liegt das Problem?• bisheriges Modell
– wir haben zwar eine Klasse Element– aber keine Klasse Liste
• Lösung: Definition einer Klasse Liste– Verweis auf das erste Element– Verweis auf das letzte Element
Problem der bisherigen Lösung
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1917
A 8x
Die Klasse „Liste“
Liste0..1kopf
0..1fuß
0..1
0..1Element
+Element(i : int)-wert : int
weiter
0..1
0..1
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1918
class Element {private int wert; private Element weiter; Element(int i) { wert = i; weiter = null; }Element(int i, Element e) { wert = i; weiter = e; }void SetzeWert(int i) { wert = i; }int GibWert() { return wert; }void SetzeWeiter(Element e) { weiter = e; }Element GibWeiter() { return weiter; }
}
Beachte: • der Konstruktor Element kann sowohl ein- als auch zweistellig
aufgerufen werden („Überladung“)
Die Klasse Element (vollständig)
neu
Diskrete Mathe11 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1919
class Liste {Liste() { kopf = fuß = null; }Liste(int w) { kopf = fuß = new Element(w); }private Element kopf, fuß;void FügeAn(int an) {
Element neu = new Element(an);if (fuß != null) {
fuß.SetzeWeiter(neu);fuß = neu;
}else
kopf = fuß = neu;}void FügeEin(int ein) {
kopf = new Element(ein, kopf);if (fuß == null)
fuß = kopf;}
}
beachte die Fallunterscheidung der leeren Liste!
Die Klasse „Liste“
leere Liste
leere Liste