Algorithmen und Datenstrukturen SS09 Foliensatz 14 Michael Brinkmeier Technische Universität Ilmenau Institut für Theoretische Informatik Sommersemester 2009 Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 1 / 35 Heapsort Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 2 / 35 Heaps Heapsort verwendet sogenannte Heaps (Haufen), d.h. Binärbäume deren Knotenmarkierungen bestimmte Bedingungen erfüllen: Definition (Max-Heap) Ein U-Binärbaum T für eine total geordnete Menge (U, <) ist ein Max-Heap (oder heißt max-heapgerodnet), wenn für jeden Knoten v gilt: Ist w ein Kind von v , dann gilt key(v ) ≥ key(w ) (Heapbedingung) 17 12 14 4 11 2 3 2 13 10 Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 3 / 35 Heaps Anstatt den Knoten größer als seine Kinder zu wählen, kann man ihn auch kleiner wählen. Definition (Min-Heap) Ein U-Binärbaum T für eine total geordnete Menge (U, <) ist ein Min-Heap (oder heißt min-heapgerodnet), wenn für jeden Knoten v gilt: Ist w ein Kind von v , dann gilt key(v ) ≤ key(w ) (Heapbedingung) 2 2 10 3 4 14 12 13 Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 4 / 35 11 17 Heaps und das Maximum Beobachtung Ist T = (T1 , x, T2 ) ein Max/Min-Heap, dann sind auch T1 und T2 Max/Min-Heaps. Lemma Ist T ein Max-Heap, dann enthält die Wurzel ein maximales Element. Beweis (Induktion über die Form von T ) Für T = (x) ist die Behauptung offensichtlich korrekt. Für T = (T1 , x, T2 ) sind die beiden Teilbäume T1 und T2 ebenfalls Max-Heaps. Damit sind die Schlüssel in ihren Wurzeln maximal in diesen Teilbäumen. Da x ≥ max{key(T1 ), key(T2 )} gilt, ergibt sich somit x ≥ key(v ) für jeden Knoten v in T . Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 5 / 35 Heaps und das Minimum Analog erhält man: Lemma Ist T ein Min-Heap, dann enthält die Wurzel ein minimales Element. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 6 / 35 Die Grundidee von Heapsort Idee Nutze Heaps, um schnell das Maximum/Minimum zu ermitteln. Heapsort läuft in zwei Phasen ab: 1 2 Bilde einen Max-Heap. Für i = n − 1, . . . , 1 tue folgendes: 1 2 Entferne das Maximum aus dem Heap und kopiere es an die letzte Stelle des Ergerbnisfeldes. Bilde aus den restlichen Elementen einen neuen Heap. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 7 / 35 Die Grundidee von Heapsort Es stellen sich mehrere Fragen: Muss man tatsächlich einen Binärbaum bauen? Wie baut man den Heap, bzw. wie stellt man die Heapbedingung her? Wie erhält man wieder einen Heap, nachdem das Maximum entfernt wurde? Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 8 / 35 Felder und binäre Bäume Wir interpretieren ein Feld A[1 . . . n] als binären Baum, indem wir beginnend mit der Wurzel, die Ebenen des Baumes sequentiell mit den Einträgen des Feldes füllen (Levelorder). Für n = 10 ergibt sich somit der folgende Baum: Tiefe 0 A[1] Tiefe 1 A[2] Tiefe 2 Tiefe 3 A[4] A[8] A[3] A[5] A[9] A[6] A[7] A[10] D.h. in Tiefe i befinden sich die Schlüssel S[2i . . . 2i +1 − 1]. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 9 / 35 Felder und binäre Bäume Tiefe 0 A[1] Tiefe 1 A[2] Tiefe 2 Tiefe 3 A[4] A[8] A[3] A[5] A[9] A[6] A[7] A[10] Die Nachfolger eines Eintrags und sein Vorgänger lassen sich auf einfache Art über die Indices im Feld ermitteln. Der linke Nachfolger von A[i] ist A[2i] Der rechte Nachfolger von A[i] ist A[2i + 1] Der Vorgänger von A[i] ist A[⌊i/2⌋] Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 10 / 35 Die Heapbedingung Die Heapbedingung lässt sich für Arrays auf die folgende Art formulieren: Definition (Array als Heap) Ein Feld A[1 . . . n] von Schlüsseln ist ein (Max-)Heap (Haufen), wenn für alle k mit 2 ≤ k ≤ n gilt A [⌊k/2⌋] ≥ A[k], d.h. der Wert des Vaters ist mindestens so groß wie jedes seiner Kinder. Für 1 ≤ l ≤ n ist A ist ein (Max-)Heap ab l, wenn für alle k mit l ≤ ⌊k/2⌋ < k ≤ n gilt A [⌊k/2⌋] ≥ A[k]. Min-Heaps sind analog definiert, lediglich die Relation zwischen Vater und Kindern ist umgedreht. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 11 / 35 Herstellen der Heapbedingung Wir betrachten einen Knoten mit Schlüssel x. Seine beiden Unterbäume T1 und T2 seien heapgeordnet. Die Wurzel von T1 sei y , und z die von T2 . x y z T1 T2 Fall 1: Wenn x ≥ y , z, dann ist der Baum bereits ein Max-Heap. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 12 / 35 Herstellen der Heapbedingung x y z T1 T2 Fall 2: Wenn y > x, z, dann muss y in die Wurzel, denn es ist der maximale Schlüssel im Baum. Anschließend muss die Heapbedingung in T1 wieder hergestellt werden. Dies erfolgt im Prinzip rekursiv. Fall 3: z > x, y wird analog behandelt. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 13 / 35 BubbleDown BubbleDown rekursiv(A, i , r ) Eingabe: Array A[1 . . . n], Länge r und Index i Voraussetzung: Die Teilbäume mit den Wurzeln 2i und 2i + 1 sind heapgeordnet. wenn (2i > r ) dann return; // j = 2i; wenn 2i + 1 ≤ r und A[2i + 1] > A[2i] dann j = 2i + 1 ; Ende wenn A[j] > x dann Vertausche A[i] und A[j]; BubbleDown rekursiv(A, j, r ); // // Algorithmen und Datenstrukturen SS09 Seite 14 / 35 A[j] ist größeres Kind Tausche Wurzel mit größerem Kind // Ende M. Brinkmeier TU Ilmenau A[i ] hat keine Nachfolger Mache bei A[j] weiter Ein Beispiel für RekHeapify 477 77 462 774 62 72 21 14 454 54 62 4 12 35 37 54 4 14 12 Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 15 / 35 BubbleDown – Iterative Formulierung BubbleDown(A, i , r ) done = false, A = A[i]; solange done == false und 2i ≤ r tue j := 2i; // Wähle das wenn 2i + 1 ≤ r und A[2i] < A[2i + 1] dann j := 2i + 1; // Falls Kind größer als Vater, schiebe Kind hoch und mache an dessen alter Position weiter wenn A < A[j] dann A[i] = A[j], i := j; // Falls Vater größer, sonst done = true; // Bringe A[i] = A; Ende höre auf die ursprüngliche Wurzel an die neue Stelle Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau größere Kind von A[j] Seite 16 / 35 BubbleDown Die Routine BubbleDown(A, i, r ) lässt somit das Element an Position i von oben nach unten an die korrekte Position sickern. Dabei ist die Voraussetzung, dass A ab 2i und 2i + 1 bereits ein Heap ist, essentiell. Korrektheit von BubbleDown ist eine Übungsaufgabe. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 17 / 35 Ablauf von Heapsort 1 Zu Beginn baut Heapsort einen Heap aus dem Feld. 2 Da wir keinerlei weitere Einschränkung machen, muss der Heap von unten nach oben gebaut werden. D.h. wir machen erst die Teilbäume zu Heaps und lassen anschließend die Wurzel mittels BubbleDown an die korrekte Position sickern. 3 Ist der Heap fertig, steht ein maximaler Schlüssel in der Wurzel. Er wird mit dem Schlüssel an der letzten Stelle des Feldes getauscht. Dadurch verkürzt sich das Feld der unsortierten Schlüssel um eins. Außerdem ist das Feld ab 2 bis n − 1 weiterhin ein Heap (durch den Tausch verändert sich nur der Wert der Wurzel). Dadurch kann es durch einen Aufruf von BubbleDown wieder zu einem Heap umgebaut werden. 4 Dies wird wiederholt, bis keine Schlüssel mehr zu sortieren sind. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 18 / 35 Heapsort Im Pseudocode hat Heapsort die folgende Form: Heapsort Beginn // Der Heap wird von unten nach oben gebaut, für j := ⌊ n2 ⌋ . . . 1 tue BubbleDown(A, j, n); beginnend in der vorletzten Ebene. // Solange noch ein Element im Heap ist, entferne das Maximum (die Wurzel) für r := n − 1 . . . 1 tue // Runterzählen von r = Verkürzung des Heaps Vertausche A[1] und A[r + 1]; // Bringe Wurzel an das Ende BubbleDown(A, 1, r ); // Wurzel muss an die korrekte Stelle sickern. Ende Ende Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 19 / 35 Korrektheit Der Beweis der Korrektheit von Heapsort ist eine Übungsaufgabe. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 20 / 35 Ein Beispiel 2 3 4 5 6 7 8 Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 30 / 35 Die Laufzeit von BubbleDown Beobachtung Für die Laufzeit von BubbleDown ist die Anzahl der Schlüsselvergleiche ausschlaggebend. In jeder Runde werden im Maximum zwei Vergleiche gemacht: 1 Vergleich der beiden Kinder, um das größere zu finden. 2 Vergleich des größeren Kindes mit dem aktuellen Knoten. Für die Runde j sei ij der Index des aktuellen Knotens. Ferner ser r der Endindex. Dann gilt offenbar ij+1 ≥ 2ij und für jede durchgeführte Runde gilt ij ≤ r . Damit gilt 2j−1 i1 ≤ ij ≤ n und somit gilt für jede durchgeführte Runde j (j − 1) + log i1 ≤ log r Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 31 / 35 Die Laufzeit von BubbleDown Lemma Beim Aufruf BubbleDown(A, i, r ) werden höchstens 2 · log r − log i Schlüsselvergleiche durchgeführt. BubbleDown(A, i, r ) benötigt im schlechtesten Fall Zeit O(log n − log i). Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 32 / 35 Laufzeit von Heapsort Betrachtet man die Aufrufe von BubbleDown, so ergeben sich die folgenden Parameterkombinationen: i r Laufzeit n .. . n .. . O(1) .. . 2 n O(log n − 1) 1 n O(log n) 1 n−1 O(log(n − 1)) 1 .. . n−2 .. . O(log(n − 2)) .. . 1 1 O(1) 2 Aufbauphase: n P O(log i) ≤ O(n log n) i =1 Wegnahmephase: n−1 P O(log i) ≤ O(n log n) i =1 Gesamt: O(n log n) Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 33 / 35 Laufzeit von Heapsort Satz Heapsort benötigt zum Sortieren eines Feldes mit n Einträgen im schlechtesten Fall O(n log n) Schlüsselvergleiche und Zeit. Bemerkungen Um absteigend zu sortieren, muss lediglich ein Min-Heap benutzt werden, d.h. die Relation in den Schlüsselvergleichen muss umgedreht werden. Die mittlere Anzahl von Vergleichen, unter der Annahme, dass jede Anordnung der Eingabeobjekte mit der WS 1/n! auftritt, ist ungefähr 2n log n. Durch eine Änderung von BubbleDown lässt sich die mittlere Zahl der Vergleiche auf n log n + O(n) senken. Bei Bottom-Up-Heapsort, wird zuerst der Weg der größeren Kinder bis zu einem Blatt verfolgt. Anschließend wird von unten die korrekte Stelle gesucht. Algorithmen und Datenstrukturen SS09 M. Brinkmeier TU Ilmenau Seite 34 / 35