Programmierung und Programmiersprachen Sommersemester 2006 Lehrstuhl für Angewandte Telematik / ee-Business Institut für Informatik Universität Leipzig Stiftungslehrstuhl der Deutschen Telekom AG [email protected] www.lpz-ebusiness.de +49 (341) 97 323 30 PuPS 24.04.2006 Doppelt verkettete Listen • Bei einfach verketteten Listen ist der Zugriff auf die Position vor dem Cursor teuer (weil noch mal vom Anfang aus dahin navigiert werden muss). • Das Traversieren (Durchlaufen) von vorne nach hinten und von hinten nach vorne ist daher asymmetrisch. • Wenn man beide Durchlaufrichtungen braucht, dann bietet es sich an, dass die Zellen in beide Richtungen verweisen. PuPS 2 1 Doppelt verkettete Listen • Nachteile: • mehr Speicherplatz, • mehr Zeiger-Setzerei beim Löschen und Einfügen • Vorteil: • schneller Zugriff in beide Richtungen PuPS 3 Bäume • Bäume sind eine fundamentale Datenstruktur, die man in vielen Bereichen der Informatik braucht. • Sie können als 2-dimensionale Verallgemeinerung von Listen aufgefasst werden. • In Bäumen lassen sich nicht nur die Daten selbst, sondern auch Beziehungen zwischen Daten ablegen, z.B. Ordnungs- oder hierarchische Beziehungen. • Daher eignen sich Bäume gut zum Wiederfinden von Daten in existierenden Ordnungen. PuPS 4 2 Binärbaum zur Repräsentation eines arithmetischen Ausdrucks PuPS 5 Implementierung von Binärbäumen Orientiert an Listen: • Statt einem Zeiger Next gibt es zwei Zeiger Links und Rechts • Statt Zelle sagt man Knoten • Cursor als Zeiger, der bei der Navigation hilft. class Knoten { Object Inhalt; Knoten links; Knoten rechts; Knoten (Object e1) {Inhalt = e1;} } PuPS 6 3 Implementierung von Binärbäumen • Ein Baum mit N Knoten hat N-1 Kanten. • Bei einer Zeiger-Darstellung eines Baums mit N Knoten gibt es daher 2 * N – (N-1) = N+1 null-Zeiger. • Ein Binärbaum ist damit ein Knoten mit ein paar Spezialoperationen: class BinaerBaum{ private Knoten Wurzel; private Knoten Cursor; boolean istLeer () { return Wurzel == null;} ... } • Anders ausgedrückt: Jeder Knoten ist die Wurzel eines Binärbaums. PuPS 7 Bäume – Graphische Darstellung der Implementation PuPS 8 4 Auf dem Weg zu HeapSort Problem: Gegeben sei ein Feld a mit n Werten, die sortiert werden müssen. Ausgangssituation: Werte im Feld sind unsortiert Ziel: sortiertes Feld Idee 1: kleinsten Wert suchen, diesen mit dem ersten Wert tauschen, fast immer sehr langsam Idee 2: benachbarte Werte tauschen, wenn der zweite Wert größer ist. Solange bis alles sortiert ist. Langsam, wenn von vorne nach hinten durchgetauscht werden muß. Idee 3: Verwendung eines Binärbaums (Heapsort) PuPS 9 Auf dem Weg zu HeapSort Wir verwenden die Zahlen 1 … n zur Nummerierung der Knoten eines binären Baums: 1 bildet die Wurzel, und der Knoten i > 1 hat i/2 als Vater, sodass der linke Sohn eines Knotens gerade und der rechte Sohn eines Knotens ungerade ist, sofern der Knoten diese Söhne hat. Damit können wir ein Feld ebenfalls als Baum darstellen: Ist das Feld a mit n Komponenten gegeben, so beschriften wir den Knoten i mit dem Feldelement a[i]. Im folgenden Beispiel haben wir das Feld mit den Elementen 7, 12, 0, 5, 9, 1, 3, 8, 13, 10, 15 als binären Baum dargestellt. Die Knoten i werden mit ihrer Beschriftung a[i] angegeben. PuPS 10 5 Auf dem Weg zu HeapSort Knoten 1 Knoten 2 Knoten 4 8 12 Knoten 3 Knoten 5 5 13 7 9 10 0 1 3 Knoten 6 Knoten 7 15 Knoten 8 Knoten 9 Knoten 10 Knoten 11 PuPS 11 Die Heap-Bedingung Ein Feld genügt der Heap-Bedingung im Knoten i, falls im Unterbaum mit Wurzel i jeder Knoten eine kleinere Beschriftung als seine Söhne trägt. Die Heap-Bedingung ist in den Knoten 3, 4, 5, 6, 7, 8, 9, 10, 11 erfüllt, nicht jedoch im Knoten 2, da a[2] = 12, a[4] = 5 und a[5] = 9 aber 12 > 5 und 12 > 9, und auch nicht im Knoten 1, da a[3] = 0 und a[0] = 7 und 7 > 0. PuPS 12 6 Lokale Gültigkeit der Heap-Bedingung Knoten 1 7 Knoten 2 12 Knoten 4 8 Knoten 3 Knoten 5 5 13 9 10 0 1 3 Knoten 6 Knoten 7 15 Knoten 8 Knoten 9 Knoten 10 Knoten 11 Heap-Bedingung im Teilbaum erfüllt PuPS 13 Auf dem Weg zu HeapSort Die Heap-Bedingung kann jedoch im Knoten 2 wie folgt hergestellt werden: Wir vertauschen die Beschriftung im Knoten 2 mit der Beschriftung desjenigen Sohnes, der die kleinere Beschriftung trägt. In diesem Fall handelt es sich um den Knoten 4. Wir nehmen hierzu die kleinere der Beschriftungen der Söhne, damit im Knoten 2 die Heap-Bedingung lokal erfüllt ist: Die Beschriftung des Knotens 2 ist kleiner als die Beschriftungen seiner Söhne (Ergebnis vgl. folgende Folie). PuPS 14 7 Auf dem Weg zu HeapSort Knoten 1 Knoten 2 8 5 Knoten 3 Knoten 5 Knoten 4 12 7 13 9 10 0 1 3 Knoten 6 Knoten 7 15 Knoten 8 Knoten 9 Knoten 10 Knoten 11 PuPS 15 Herstellung der lokalen HeapHeap-Bedingung im Knoten 2 Knoten 1 Knoten 2 8 5 Knoten 3 Knoten 5 Knoten 4 12 13 7 10 9 0 1 3 Knoten 6 Knoten 7 15 Knoten 8 Knoten 9 Knoten 10 Knoten 11 PuPS 16 8 Auf dem Weg zu HeapSort • Nun ist zwar die Heap-Bedingung im Knoten 2 lokal hergestellt. Als Folge ist sie aber im Knoten 4 verletzt! • Die Vertauschung der Beschriftung eines Knotens mit der kleineren Beschriftung eines seiner Söhne, lässt sich an dieser Stelle wiederholen, sodass die Beschriftung 12 in ein Blatt, den Knoten 8, wandert. • Trivialerweise ist die Heap-Bedingung in einem Blatt erfüllt, sodass wir durch das beschriebene Vorgehen schrittweise dafür gesorgt haben, dass die Heap-Bedingung im Knoten 2 hergestellt wurde. PuPS 17 Auf dem Weg zu HeapSort Knoten 1 Knoten 2 Knoten 4 12 8 5 Knoten 3 Knoten 5 13 7 10 9 0 1 3 Knoten 6 Knoten 7 15 Knoten 8 Knoten 9 Knoten 10 Knoten 11 PuPS 18 9 Auf dem Weg zu HeapSort Knoten 1 Knoten 2 Knoten 4 12 8 5 Knoten 3 Knoten 5 13 7 9 10 0 1 3 Knoten 6 Knoten 7 15 Knoten 8 Knoten 9 Knoten 10 Knoten 11 PuPS 19 Auf dem Weg zu HeapSort • Die Heap-Bedingung gilt aber immer noch nicht für den Knoten 1, da die Beschriftungen beider Söhne, der Knoten 2 und 3 kleiner sind als die Beschriftung der Wurzel des Baumes. PuPS 20 10