400 likes | 559 Views
Diskrete Mathematik I. Vorlesung 5 11.11.99 -Listen-. Rekursion. letzte Stunde: rekursive Definitionen und Methoden heute: rekursive Datenstrukuren: Listen. Übersicht. Listen ... als rekursive Struktur ... als dynamische Datenstrukturen Die Klasse Element
E N D
Diskrete Mathematik I Vorlesung 5 11.11.99 -Listen-
Rekursion • letzte Stunde: rekursive Definitionen und Methoden • heute: rekursive Datenstrukuren: Listen
Übersicht • 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 (Fortsetzung) • 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“
Listen als rekursive Struktur • Die leere Liste Null ist eine Liste. • Wenn E ein Element ist und L eine Liste, dann istE L eine Liste. • Beispiele: • die leere Liste { } • {1} • {1,3,2,5} • Graphik für die leere Liste:
Listen als Dynamische Datenstrukturen • flexible Datenstruktur ohne vorherige Festlegungauf 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
5 Die Klasse Element classElement { int wert; Element weiter; } Element int Zeiger auf ein Element
... mit Element-konstruktor classElement { Element(int i) { wert = i; weiter = null;} int wert; Element weiter;} Das ist neu • Die ProzedurElement(int i)ist ein Konstruktor, der bei der Erzeugung eines Elements mit new Element(i) automatisch aufgerufen wird.
5 3 7 Der Rest der Liste Eine richtige kleine Liste DerKopf der Liste Die leereListe
Ein UML-Diagramm für „Element“ Element Ein oderkein Nachfolger 0..1 -wert : int Beziehung Konstruktor weiter +Element(i : int) 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 0..1
Aber wie kommt man nun zu einer Liste? • 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 Elemente • zusätzliche Prozedur
Anfügen von Elementen Sucht das letzte Element void FügeAn(int neuerWert) { Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert); } Zeiger auf dasaufrufende Objekt fügt neues Element an
kopf Element kopf; class Element { Element(int i) { wert = i; weiter = null; } int wert; Element weiter; }
kopf Element kopf; kopf = new Element(25); class Element { Element(int i) { wert = i; weiter = null; } int wert; Element weiter; }
kopf Element kopf; kopf = new Element(25); 25 class Element { Element(int i) { wert = i; weiter = null; } int wert; Element weiter; }
25 kopf 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 Element kopf; kopf = new Element(25); kopf.FügeAn(22); lauf void FügeAn(int neuerWert) { Element lauf = this; while (lauf.weiter!= null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert); }
25 22 kopf 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 22 kopf 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 22 kopf 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); }
25 22 kopf Element kopf; kopf = new Element(25); kopf.FügeAn(22); kopf.FügeAn(28); lauf void FügeAn(int neuerWert) { Element lauf = this; while (lauf.weiter!= null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert); }
25 22 kopf Element kopf; kopf = new Element(25); kopf.FügeAn(22); kopf.FügeAn(28); lauf void FügeAn(int neuerWert) { Element lauf = this; while (lauf.weiter != null) lauf=lauf.weiter; lauf.weiter = new Element(neuerWert); }
25 22 kopf Element kopf; kopf = new Element(25); kopf.FügeAn(22); kopf.FügeAn(28); lauf void FügeAn(int neuerWert) { Element lauf = this; while (lauf.weiter!= null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert); }
25 28 22 kopf Element kopf; kopf = new Element(25); kopf.FügeAn(22); kopf.FügeAn(28); lauf void FügeAn(int neuerWert) { Element lauf = this; while (lauf.weiter != null) lauf = lauf.weiter; lauf.weiter = new Element(neuerWert); }
25 28 22 kopf 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); }
25 28 22 kopf 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); }
15 22 28 15 22 28 17 Problem: Einfügen am Anfang einer Liste • 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 kopf kopf
Einfügen am Anfang einer Liste void FügeEin(intneuerWert) { Element neuesElement = new Element(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
25 22 28 Einfügen am Anfang einer Liste kopf kopf.FügeEin(17) void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
25 22 28 25 Einfügen am Anfang einer Liste kopf neuesElement void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
25 22 28 25 Einfügen am Anfang einer Liste kopf neuesElement void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
25 22 28 25 Einfügen am Anfang einer Liste kopf void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
25 22 28 25 Einfügen am Anfang einer Liste kopf void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
25 22 28 25 Einfügen am Anfang einer Liste kopf void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
17 22 28 25 Einfügen am Anfang einer Liste kopf void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
17 22 28 25 Einfügen am Anfang einer Liste kopf void FügeEin(int neuerWert) { Element neuesElement = newElement(wert); neuesElement.weiter = weiter; weiter = neuesElement; wert = neuerWert; }
Problem der bisherigen Lösung • 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
kopf Liste Element 0..1 -wert : int weiter +Element(i : int) fuß 0..1 Die Klasse „Liste“ 0..1 0..1 0..1 0..1
Die Klasse Element (vollständig) 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 weden („Überladung“) neu
Die Klasse „Liste“ 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! leere Liste leere Liste