112 Algorithmen und Datenstrukturen 5 Heapsort In diesem Kapitel wird Heapsort, ein weiterer Sortieralgorithmus, vorgestellt. Dieser besitzt wie M ERGE -S ORT eine Laufzeit von O(n log n), sortiert jedoch das Eingabefeld an Ort und Stelle (in-place), d.h. zu jeder Zeit wird höchstens eine konstante Anzahl Elemente außerhalb des Datenfeldes zwischengespeichert. Eine weitere Besondeheit von Heapsort ist die Verwendung einer Datenstruktur, in diesem Fall ein sog. Heap, um während des Algorithmus die Daten effizient zu verwalten. Wir verweisen auf Anhang 2 der Folien für einige in diesem Abschnitt auftretende Definitionen und Sprechweisen aus der elementaren Graphentheorie und wenden uns dann der Heap-Datenstruktur zu. 5 Heapsort TU Bergakademie Freiberg, WS 2005/06 113 Algorithmen und Datenstrukturen 5.1 Heaps Ein (binärer) Heap ist ein Zahlenfeld, das als (fast) vollständigen Binärbaum betrachtet werden kann. Jeder Knoten des Baumes entspricht einem Feldelement, in dem der Wert dieses Knoten gespeichert ist. Der Baum ist vollständig auf allen Ebenen außer der untersten, welche von links nach rechts aufgefüllt wird. Ein Feld A, welches einen Heap darstellt, besitzt die zwei Attribute • length[A]: die Anzahl Elemente in A. • heap-size[A]: die Anzahl Elemente im Heap, der in A dargestellt wird. Genauer: Obwohl A[1 . . length[A]] gültige Werte enthalten mag, sind nur die Feldelemente zwischen 1 und heap-size[A] ≤ length[A] Elemente des Heaps. 5.1 Heaps TU Bergakademie Freiberg, WS 2005/06 114 Algorithmen und Datenstrukturen Die Wurzel des Baumes ist A[1]. Ist i der Index eines Knotens, so können Index von Vater sowie linkem und rechtem Sohn berechnet werden gemäß PARENT(i) return bi/2c L EFT(i) return 2i R IGHT(i) return 2i + 1 Berechnung anhand der Binärdarstellung von i: L EFT: Verschieben um eine Position nach links R IGHT: zusätzlich Addition von 1 im niedrigstwertigem Bit PARENT: Verschieben um eine Position nach rechts 5.1 Heaps TU Bergakademie Freiberg, WS 2005/06 115 Algorithmen und Datenstrukturen Man unterscheidet zwei Arten von Heaps: in beiden genügen die in den Knoten enthaltenen Werten einer Heap-Bedingung. • Max-Heap: die Max-Heap Eigenschaft besagt, dass für jeden Knoten bis auf die Wurzel gilt A[PARENT(i)] ≥ A[i], d.h. das größte Element eines Max-Heaps sitzt an der Wurzel. • Min-Heap: die Min-Heap Eigenschaft besagt, dass für jeden Knoten bis auf die Wurzel gilt A[PARENT(i)] ≤ A[i], d.h. das kleinste Element eines Min-Heaps sitzt an der Wurzel. In den im Knoten mit Wert i wurzelnden Teilbäumen befinden sich demnach ausschließlich Knoten, mit Wert ≤ A[i] (≥ A[i]). 5.1 Heaps TU Bergakademie Freiberg, WS 2005/06 116 Algorithmen und Datenstrukturen 1 16 2 3 14 10 4 5 6 7 8 7 9 3 8 9 10 1 2 3 4 5 6 7 8 9 10 2 4 1 16 14 10 8 7 9 3 2 4 1 Ein Max-Heap in Binärbaum- und Felddarstellungen. Die Zahlen in den Knoten sind die darin gespeicherten Werte, die kleinen Zahlen darüber geben den Feldindex des Knotens an. Die roten und grünen Kanten im Baum bzw. die Verbindungslinien im Feld geben die rechten und linken Sohnbeziehungen an. 5.1 Heaps TU Bergakademie Freiberg, WS 2005/06 117 Algorithmen und Datenstrukturen Für jeden Knoten in einem Heap definieren wir dessen Höhe als Länge des kürzesten einfachen absteigenden Wegens von diesem Knoten zu einem Blatt. Die Höhe des Heaps sei die Höhe dessen Wurzel. Da ein Heap mit n Elementen wie ein Binärbaum angeordnet ist, verhält sich dessen Höhe wie Θ(log n). Grundoperationen an einem Heap proportional zu dessen Höhe erfordern also O(log n) Zeit/Aufwand. 5.1 Heaps TU Bergakademie Freiberg, WS 2005/06 118 Algorithmen und Datenstrukturen Im Folgenden: Heap Grundoperationen • M AX -H EAPIFY: erhält die Max-Heap Eigenschaft [O(log n)] • B UILD -M AX -H EAP: erzeugt Max-Heap aus unsortiertem Eingabefeld [O(n)] • H EAPSORT: Sortiert ein Zahlenfeld [O(n log n)] • M AX -H EAP -I NSERT, H EAP -E XTRACT-M AX, H EAP -I NCREASE -K EY und H EAP -M AXIMUM ermöglichen die Implementierung einer Prioritätsschlange (priority queue) durch einen Heap. [O(log n)] 5.1 Heaps TU Bergakademie Freiberg, WS 2005/06 119 Algorithmen und Datenstrukturen 5.2 Erhaltung der Heap Eigenschaft Wir betrachten die Grundoperation M AX -H EAPIFY. • Wichtige Prozedur bei der Manipulation eines Heaps • Eingaben: ein Feld A und ein Index i in das Feld • Grundannahme: die bei L EFT(i) und R IGHT(i) wurzelnden Teilbäume sind bereits Max-Heaps, aber A[i] möglicherweise kleiner als ein Nachfolger (somit Max-Heap Eigenschaft möglicherweise verletzt). • Vorgehen: A[i] wandert den Baum hinab, bis der in i wurzelnde Teilbaum ebenfalls ein Max-Heap geworden ist. 5.2 Erhaltung der Heap Eigenschaft TU Bergakademie Freiberg, WS 2005/06 Algorithmen und Datenstrukturen 120 M AX -H EAPIFY(A, i) 1 2 3 4 5 6 7 8 9 10 ` ← L EFT(i) r ← R IGHT(i) if ` ≤ heap-size[A] and A[`] > A[i] then largest ← ` else largest ← i if r ≤ heap-size[A] and A[r] > A[largest] then largest ← r if largest 6= i then vertausche A[i] ↔ A[largest] M AX -H EAPIFY(A, largest) 5.2 Erhaltung der Heap Eigenschaft TU Bergakademie Freiberg, WS 2005/06 121 Algorithmen und Datenstrukturen • In Zeilen 1-7 wird festgestellt, welcher Knoten unter A[i] und dessen Söhnen den größten Wert enthält. • Ist dies A[i] selbst, so ist der in i wurzelnde Teilbaum bereits ein Max-Heap und der Algorithmus terminiert. • Befindet sich das größte Element im linken Sohn, so wird dies mit A[i] vertauscht. Der im rechten Sohn wurzelnde Teilbaum bleibt daher unverändert, ist also nach wie vor ein Max-Heap. Beim im linken Sohn wurzelnden Teilbaum muss die Max-Heap-Eigenschaft hingegen durch einen rekursiven Aufruf von M AX -H EAPIFY geprüft werden. 5.2 Erhaltung der Heap Eigenschaft TU Bergakademie Freiberg, WS 2005/06 122 Algorithmen und Datenstrukturen Beispiel für Aufruf M AX -H EAPIFY(A, 2): In der Ausgangskonfiguration verletzt der Knoten 2 die Max-Heap Bedingung. 1 16 2 3 4 10 4 5 6 7 14 7 9 3 8 9 10 2 8 1 5.2 Erhaltung der Heap Eigenschaft TU Bergakademie Freiberg, WS 2005/06 122 Algorithmen und Datenstrukturen Beispiel für Aufruf M AX -H EAPIFY(A, 2): In der Ausgangskonfiguration verletzt der Knoten 2 die Max-Heap Bedingung. 1 16 2 3 14 4 10 4 5 6 7 14 4 7 9 3 8 9 10 2 8 1 5.2 Erhaltung der Heap Eigenschaft TU Bergakademie Freiberg, WS 2005/06 122 Algorithmen und Datenstrukturen Beispiel für Aufruf M AX -H EAPIFY(A, 2): In der Ausgangskonfiguration verletzt der Knoten 2 die Max-Heap Bedingung. 1 16 2 3 14 4 10 4 5 6 7 14 48 7 9 3 8 9 10 2 84 1 5.2 Erhaltung der Heap Eigenschaft TU Bergakademie Freiberg, WS 2005/06 123 Algorithmen und Datenstrukturen Laufzeit von M AX -H EAPIFY angewandt auf Teilbaum der Größe n mit Wurzel i. • Bestimmung des größten Elementes unter A[i], A[L EFT(i)] und A[R IGHT(i)] mit eventuellem Vertauschen: Θ(1). • Jeder Teilbaum besitzt höchstens 2n/3 Elemente. (Extremfall: ein Teilbaum voll besetzt, der andere minimal besetzt) • Damit erfüllt Laufzeit die Rekursion T (n) ≤ T (2n/3) + Θ(1). Hauptsatz (Fall 2): T (n) = Θ(log n) = Θ(h) (h die Höhe des Teilbaums). 5.2 Erhaltung der Heap Eigenschaft TU Bergakademie Freiberg, WS 2005/06 124 Algorithmen und Datenstrukturen 5.3 Konstruktion eines Heap Idee: Wiederholte Anwendung von M AX -H EAPIFY zur Umwandlung eines Eingabefeldes A[1 . . n] der Länge n in einen Max-Heap. Vorgehen von Unten nach Oben: Im Baum, der dem Feld A[1 . . n] entspricht, besitzen die Blätter die Indices bn/2c + 1, . . . , n (siehe 4. Übungsblatt). Die Blätter sind einelementige Heaps. Der Algorithmus B UILD -M AX -H EAP wendet M AX -H EAPIFY sukzessive auf die verbleibenden Knoten an: B UILD -M AX -H EAP(A) 1 heap-size[A] ← length[A] 2 for i ← blength[A]/2c downto 1 3 do M AX -H EAPIFY(A,i) 5.3 Konstruktion eines Heap TU Bergakademie Freiberg, WS 2005/06 125 Algorithmen und Datenstrukturen 1 4 5.3 Konstruktion eines Heap 2 3 1 3 4 5 6 7 2 16 9 10 8 9 10 14 8 7 TU Bergakademie Freiberg, WS 2005/06 125 Algorithmen und Datenstrukturen 1 4 5.3 Konstruktion eines Heap 2 3 1 3 4 5 6 7 22 16 9 10 8 9 10 14 8 7 TU Bergakademie Freiberg, WS 2005/06 125 Algorithmen und Datenstrukturen 1 4 5.3 Konstruktion eines Heap 2 3 1 3 4 5 6 7 22 14 16 9 10 8 9 10 14 2 8 7 TU Bergakademie Freiberg, WS 2005/06 125 Algorithmen und Datenstrukturen 1 4 5.3 Konstruktion eines Heap 2 3 1 10 3 4 5 6 7 22 14 16 9 10 3 8 9 10 14 2 8 7 TU Bergakademie Freiberg, WS 2005/06 125 Algorithmen und Datenstrukturen 1 4 5.3 Konstruktion eines Heap 2 3 1 16 10 3 4 5 6 7 22 14 16 7 9 10 3 8 9 10 14 2 8 71 TU Bergakademie Freiberg, WS 2005/06 125 Algorithmen und Datenstrukturen 1 4 16 5.3 Konstruktion eines Heap 2 3 14 1 16 10 3 4 5 6 7 282 14 16 7 9 10 3 8 9 10 14 2 84 71 TU Bergakademie Freiberg, WS 2005/06 126 Algorithmen und Datenstrukturen Schleifeninvariante (SI) für B UILD -M AX -H EAP: Vor jedem Durchlauf der for -Schleife (Zeilen 2-3) sind die Knoten mit Indizes i + 1, . . . , n Wurzeln eines Max-Heaps. Initialisierung: Vor erstem Durchlauf gilt i = bn/2c. Knoten mit Indizes i + 1, . . . , n allesamt Blätter und somit Wurzeln von (einelementigen) Max-Heaps. Erhaltung: Söhne von Knoten i besitzen höhere Indices, sind nach SI somit Wurzeln von Max-Heaps. Unter dieser Voraussetzung ist nach der Ausführung von M AX -H EAPIFY(A, i) Knoten i Wurzel eines Max-Heaps. Ferner erhält die Ausführung die Max-Heap Eigenschaft der Knoten i + 1, . . . , n. Damit gilt die Schleifeninvariante auch nach Ausführung der for -Schleife für den Index i − 1. Terminierung: Erfolgt bei i = 0, SI: alle Knoten – insbesondere Knoten 1 – sind Wurzeln eines Max-Heaps. 5.3 Konstruktion eines Heap TU Bergakademie Freiberg, WS 2005/06 127 Algorithmen und Datenstrukturen Laufzeit von B UILD -M AX -H EAP: • Obere Schranke: jede der O(n) Ausführungen von M AX -H EAPIFY erfordert O(log n) Zeit, damit ist Laufzeit O(n log n). Diese Schranke ist nicht scharf. • Scharfe obere Schranke beruht auf 2 Beobachtungen: ◦ Laufzeit von M AX -H EAPIFY hängt ab von Höhe h = blog2 nc des Knotens (n Größe des an diesem Knoten wurzelnden Teilbaums). ◦ Ferner: n-elementiger Teilbaum enthält höchstens dn/2h+1 e Knoten der Höhe h (siehe 4. Übungsblatt). 5.3 Konstruktion eines Heap TU Bergakademie Freiberg, WS 2005/06 128 Algorithmen und Datenstrukturen Laufzeit von M AX -H EAPIFY angewandt auf Knoten der Höhe h: O(h). Damit Gesamtlaufzeit von B UILD -M AX -H EAP gegeben durch blog2 nc blog2 nc X X h n d h+1 eO(h) = O n h 2 2 h=0 h=0 Wegen blog2 nc X h=0 h = h 2 blog2 nc X h=0 h X h ∞ 1 1 1/2 h < h = =2 2 2 2 (1 − 1/2) h=0 folgt blog2 nc X h=0 n d h+1 eO(h) = O n 2 5.3 Konstruktion eines Heap blog2 nc X h=0 h =O n 2h ∞ X h=0 h 2h ! = O(n). TU Bergakademie Freiberg, WS 2005/06 129 Algorithmen und Datenstrukturen Fazit: Die Konstruktion eines Max-Heaps aus einem unsortierten Eingabefeld erfordert linearen Zeitaufwand. All diese Überlegungen gelten entsprechend für Min-Heaps mit offensichtlichen Modifikationen. 5.3 Konstruktion eines Heap TU Bergakademie Freiberg, WS 2005/06 130 Algorithmen und Datenstrukturen 5.4 Der Heapsort-Algorithmus Vorgehen: • Gegeben: (aufsteigend) zu sortierendes Eingabefeld A[1 . . n] der Länge n. • Konstruktion eines Max-Heaps aus A mittels B UILD -M AX -H EAP • Da das größte Element eines Max-Heaps an der Wurzel sitzt, kann dieses durch Vertauschen mit A[n] bereits an seine endgültige Position im sortierten Feld gebracht werden. • Entferne A[n] aus dem Heap, d.h. betrachte A[1 . . n − 1]. • Für A[1 . . n − 1] kann durch Ausführen von M AX -H EAPIFY(A, 1) die Max-Heap Eigenschaft wiederhergestellt werden. 5.4 Der Heapsort-Algorithmus TU Bergakademie Freiberg, WS 2005/06 131 Algorithmen und Datenstrukturen Pseudocode: H EAPSORT(A) 1 B UILD -M AX -H EAP(A) 2 for i ← length[A] downto 2 3 do vertausche A[1] ↔ A[i] 4 heap-size[A] ← heap-size[A] − 1 5 M AX -H EAPIFY(A, 1) Laufzeit: 1 Ausführung von B UILD -M AX -H EAP O(n) n − 1 Ausführungen von M AX -H EAPIFY je O(log n) Insgesamt: O(n log n) 5.4 Der Heapsort-Algorithmus TU Bergakademie Freiberg, WS 2005/06