Mergesort - Sortieren durch Mischen Algorithmen und Datenstrukturen 10. Vorlesung Ein divide-and-conquer“-Algorithmus ” Algorithmus mergeSort(a, b) (1) if b − a ≥ 1 then (Korrektur!) (2) m ← (b − a) div 2; (3) mergeSort(a, m); (4) mergeSort(m + 1, b); (5) merge(a, m, b). Martin Dietzfelbinger 13. Juni 2005 Um A[1 . . n] zu sortieren: mergeSort(1, n). Interessant: Alle Vergleiche in merge(a, m, b). FG KTuEA, TU Ilmenau AuD – 13.06.2005 FG KTuEA, TU Ilmenau AuD – 13.06.2005 1 Dabei: Prozedur merge(a, m, b), 1 ≤ a ≤ m < b ≤ n: Zeitanalyse ergibt: Aufwand Θ(n log n). Voraussetzung: A[a . . m] und A[m + 1 . . b] sind sortiert. Beweis: mit Rekursionsungleichung (schon gesehen). Resultat: A[a . . b] ist sortiert. Alternative: Direkte Analyse, Induktionsbeweis. Aufwand: ≤ b − a Schlüsselvergleiche, Zeit Θ(b − a + 1). TMS(k) seien die Kosten eines Aufrufs mergeSort(a, b), auf k = b − a + 1 Schlüsseln, im schlechtesten Fall. Es gibt Konstante c > 0 und d > 0 mit TMS(1) ≤ c; TMS(k) ≤ d · k + TMS(bk/2c) + TMS(dk/2e), für k ≥ 2. Trick: Lösung mit Parametern A, B raten; der Induktionsbeweis liefert die richtigen Parameter. FG KTuEA, TU Ilmenau AuD – 13.06.2005 2 FG KTuEA, TU Ilmenau AuD – 13.06.2005 3 TMS(1) ≤ c; TMS(k) ≤ d · k + TMS(bk/2c) + TMS(dk/2e), für k ≥ 2. TMS(k) ≤ I.V. ≤ Behauptung: TMS(k) ≤ A · k + B · k log k, für alle k ≥ 1. d · k + TMS(bk/2c) + TMS(dk/2e) d · k + Abk/2c + Bbk/2c logbk/2c + Adk/2e + Bdk/2e logdk/2e Beweis: Induktion über k. ≤ k = 1: TMS(1) ≤ c ≤ A · k, falls A ≥ c. d · k + Ak + Bk logdk/2e . | {z } ≤ log(k/2)+ 21 k ≥ 2: Also: 1 TMS(k) ≤ (d + A − B)k + Bk log k. 2 Mit A = c und B = 2d funktioniert der Induktionsbeweis. Analog zeigt man: TMS(k) ≥ A0k +B 0k log k, für gewisse Konstanten A0, B 0 > 0. FG KTuEA, TU Ilmenau AuD – 13.06.2005 4 FG KTuEA, TU Ilmenau AuD – 13.06.2005 5 Satz Variante 1: (Standardmäßig angewandt) Der Aufruf mergeSort(1, n) für ein Array mit n Einträgen benötigt Ziel: Überproportional hohen Zeitaufwand für (rekursive) Prozedur-Aufrufe bei kleinen Teilarrays vermeiden. Strategie: In mergeSort kleine Teilarrays (b − a ≤ ∆, m − a ≤ ∆, b − (m + 1) ≤ ∆, ∆ ≥ 1 konstant) direkt durch (z. B.) Straight-Insertion-Sort sortieren. • höchstens n log n Vergleiche und • hat Kosten (Laufzeit) O(n log n). Mergesort ist stabil (wenn merge stabil programmiert wird). Bemerkung: Mergesort benötigt zusätzlichen Speicherplatz (bis zu n/2 Arrayeinträge), ist also nicht in situ“. ” FG KTuEA, TU Ilmenau AuD – 13.06.2005 6 FG KTuEA, TU Ilmenau AuD – 13.06.2005 7 Algorithmus mergeSortV1(a, b) (1) if b − a ≤ ∆ (2) then SIS(a, b) (3) else m ← (b − a) div 2; (4) Variante 2: Mergesort für (einfach verkettete lineare) Listen. Wenn die Liste L nur ein Element enthält, ist nichts zu tun. Andernfalls wird die Liste in 2 Teillisten L1, L2 der halben Länge zerteilt. (5) if m − a ≤ ∆ then SIS(a, m) else mergeSort(a, m); (Durchlaufe L, hänge die Einträge abwechselnd an L1 und L2 an. — Kosten: Θ(Länge von L).) (6) if b − m < ∆ then SIS(m + 1, b) else mergeSort(m + 1, b); Auf L1 und L2 wird der Algorithmus rekursiv angewendet. (7) merge(a, m, b). Dann werden die beiden nun sortierten Listen gemischt“ — ” zu einer sortierten Liste zusammengefügt. (Vgl. Übung zu dünn besetzten Matrizen.) SIS(a, b): Sortiert A[a . . b] mittels Straight-Insertion-Sort. Als ∆ kommen z.B. Werte 6, 8 oder 10 in Frage. Das optimale ∆ für eine konkrete Maschine kann ein Experiment liefern. FG KTuEA, TU Ilmenau AuD – 13.06.2005 8 Variante 3: Iteratives Mergesort, bottom-up“ ” Idee: Arbeite in Runden i = 1, 2, 3, . . . , dlog ne. Laufzeitanalyse: Identisch zur Array-Variante. FG KTuEA, TU Ilmenau Runde merge((l − 2)2i + 1, (l − 1)2i, l2i) A: 7 2 9 6 3 1 6 10 2 17 12 6 2 7 4 C: 2 7 6 9 1 3 6 10 2 17 6 12 2 7 4 A: 2 6 7 9 1 3 6 10 2 6 12 17 2 4 7 C: 1 2 3 6 6 7 9 10 2 2 4 6 7 12 17 A: 1 2 2 2 3 4 6 6 7 7 9 10 12 17 1 2 In Runde i führe 3 aus, für l = 2, 4, . . . , 2bn/2i+1c. (Mögliche Sonderrolle für unvollständige Teilarrays ganz rechts.) AuD – 13.06.2005 9 Beispiel: Vor Runde i: Teilarrays A[(l − 1)2i + 1 . . l2i] sind aufsteigend sortiert. (Eventuell ist das am weitesten rechts stehende Teilarray unvollständig.) FG KTuEA, TU Ilmenau AuD – 13.06.2005 10 4 FG KTuEA, TU Ilmenau AuD – 13.06.2005 6 11 Trick, spart Kopierarbeit: Benutze 2 Arrays, die in jeder Runde ihre Rolle wechseln. Variante 4: Mehrweg-Mergesort Besonders in Kombination mit dem iterativen Verfahren interessant ist die Möglichkeit, in einer merge-Runde nicht nur ein Array, sondern 3, 4, oder mehr Teilarrays zusammenzumischen. Zeitverhalten von iterativem Mergesort: wie bei rekursivem Mergesort. Bei dieser Variante bietet sich noch eine alternative, einfache Zeitanalyse an: Beispiel: 1 7 9 13 2 5 7 9 3 6 6 10 2 4 11 12 A: Jede Runde kostet offenbar Zeit Θ(n), und es gibt dlog ne Runden: also ist die Gesamtzeit Θ(ndlog ne) = Θ(n log n). 4−way merge: wähle kleinstes Element aus 4 (Rest−)Arrays. C: 1 2 2 3 4 5 6 6 7 7 Die nächsten gewählten Elemente: "9" aus 1.Teilarray, "9" aus 2. Teilarray, 10, 11, etc. FG KTuEA, TU Ilmenau AuD – 13.06.2005 12 Bei Cache-Architekturen oder Sortieren von Daten auf Hintergrundspeichern (Platten) kann diese Variante Laufzeitvorteile bringen, da die Anzahl der Cache- bzw. Seitenfehler (cache misses bzw. page faults) verringert wird. FG KTuEA, TU Ilmenau AuD – 13.06.2005 13 Ein Vergleich: 10n log n versus n2/5 n log n versus n*n, bis n=500 50000 40000 Früher: Sortieren von Daten auf Bändern. Algorithmus der Wahl: Mergesort. 30000 20000 10000 0 100 200 x 300 400 500 10*n*log n n*n/5 FG KTuEA, TU Ilmenau AuD – 13.06.2005 14 FG KTuEA, TU Ilmenau AuD – 13.06.2005 15 Ein Vergleich: 10n log n versus n2/5 Ein Vergleich: 10n log n versus n2/5 n log n versus n*n, bis n=3000 n log n versus n*n, bis n=10000 1.8e+06 2e+07 1.6e+06 1.4e+06 1.5e+07 1.2e+06 1e+06 1e+07 800000 600000 5e+06 400000 200000 0 500 1000 1500 2000 x 2500 0 3000 2000 4000 10*n*log n n*n/5 FG KTuEA, TU Ilmenau 6000 x 8000 10000 10*n*log n n*n/5 AuD – 13.06.2005 16 FG KTuEA, TU Ilmenau AuD – 13.06.2005 Ein Vergleich: 10n log n versus n2/5 17 Heapsort Heap-Ordnung in Binärbaumen: n log n versus n*n, bis n=1000000 Beispiel: 1e+11 3 min: 17 max: 8e+10 10 6e+10 4e+10 12 4 12 12 3 5 12 10 3 2e+10 5 12 0 200000 400000 x 600000 800000 1e+06 12 10*n*log n n*n/5 17 3 4 Hier nur interne Knoten relevant. Blätter: Knoten ohne (interne) Kinder. FG KTuEA, TU Ilmenau AuD – 13.06.2005 18 FG KTuEA, TU Ilmenau AuD – 13.06.2005 19 Definition Ein Binärbaum T mit Knotenbeschriftungen m(v) aus (U, <) heißt min-heapgeordnet (oft: heapgeordnet), wenn für jeden Knoten v gilt: w Kind von v ⇒ m(v) ≤ m(w). Ein linksvollständiger Binärbaum: Alle Levels j = 0, 1, . . . voll (2j Knoten) bis auf die tiefste. Das tiefste Level l hat von links her gesehen eine ununterbrochene Folge von Knoten. NB: In v steht der minimale Eintrag des gesamten Teilbaums Tv mit Wurzel v. (T heißt max-heapgeordnet, wenn für jeden Knoten v gilt: w Kind von v ⇒ m(v) ≥ m(w).) FG KTuEA, TU Ilmenau AuD – 13.06.2005 20 Numerierung von Knoten in unendlichem, vollständigen Binärbaum gemäß Breitendurchlauf-Anordnung: Beispiel: (101110)2 = 46 1 1 0 2 0 1 5 0 1 0 0 11 10 9 1 7 6 1 12 1 0 1 0 14 13 1 0 1 0 1 0 15 0 32 FG KTuEA, TU Ilmenau 1 1 46 47 63 0 AuD – 13.06.2005 21 1 ist die Wurzel; 2i ist linkes Kind von i; 2i + 1 ist rechtes Kind von i; i ≥ 2 hat Vater bi/2c. Beobachte: Ein linksvollständiger Binärbaum besteht aus einem Anfangsabschnitt {1, 2, . . . , n} der Knoten des unendlichen vollständigen Binärbaums (mit denselben Vater-SohnBeziehungen). 1 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 AuD – 13.06.2005 Ist s1 · · · sl ∈ {0, 1}l die Markierung auf dem Weg von der Wurzel zu Knoten i auf Level l, so ist 1s1 · · · sl die Binärdarstellung von i. Knoten Knoten Knoten Knoten 1 0 0 1 8 0 3 4 0 1 FG KTuEA, TU Ilmenau 22 FG KTuEA, TU Ilmenau AuD – 13.06.2005 23 Idee: Array-Darstellung für linksvollständige Binärbaume. Kombiniere Heapbedingung und Array-Darstellung: Speichere Knoten-Einträge in Array A[1 . . n]. Definition Beispiel: n = 26 Knoten: Array A[1 . . n] mit Einträgen aus (U, <) heißt ein MinHeap (oder Heap), wenn der entsprechende linksvollständige Binärbaum mit n Knoten (Knoten i mit A[i] beschriftet) (min-)heapgeordnet ist. 1 3 2 4 5 8 9 10 6 11 20 21 22 23 16 17 18 19 7 13 12 D. h.: A[1 . . n] ist Heap, falls für 1 ≤ i ≤ n gilt: 2i ≤ n ⇒ A[i] ≤ A[2i] und 2i + 1 ≤ n ⇒ A[i] ≤ A[2i + 1]. 14 15 Analog: Max-Heap (benutze Maxheap-Ordnung.) 24 25 26 Spart den Platz für die Zeiger! FG KTuEA, TU Ilmenau AuD – 13.06.2005 24 U = {A, B, C, . . . , Z} mit der Standardordnung. FG KTuEA, TU Ilmenau AuD – 13.06.2005 Heaps reparieren: 25 bubble-down“ ” Ein Min-Heap und der zugeordnete Baum: 1 10 A B E F C G J H I D A: 1 D 2 1 * 3 A C A 4 2 B E 4 5 C F 8 I 7 E J I G J Fehler ∗ nur an der Wurzel. Beide Unterbäume sind heapgeordnet. D AuD – 13.06.2005 6 9 10 H 7 9 10 H FG KTuEA, TU Ilmenau 8 6 G 5 B F 3 26 FG KTuEA, TU Ilmenau AuD – 13.06.2005 27 Heaps reparieren: bubble-down“ ” 1 D 2 1 D 3 2 C 5 6 B F J FG KTuEA, TU Ilmenau 5 bubble-down“ ” FG KTuEA, TU Ilmenau AuD – 13.06.2005 Heaps reparieren: 29 bubble-down“ ” 1 A A * 3 D 5 B F 8 6 I J 5 B F 8 G AuD – 13.06.2005 3 C 4 7 E * D 9 10 H FG KTuEA, TU Ilmenau 2 C 4 J G 1 2 7 E 9 10 I H 28 6 B 8 AuD – 13.06.2005 Heaps reparieren: 3 C F G * A 4 7 E 9 10 I H bubble-down“ ” * A 4 8 Heaps reparieren: FG KTuEA, TU Ilmenau 7 E J 9 10 H 30 6 I G AuD – 13.06.2005 31 Heaps reparieren: bubble-down“ ” Prozedur bubbleDown(1, k) (∗ Heapreparatur in A[1 . . k] ∗) (1) j ← 1; done ← false; (2) while not done and 2 ∗ j + 1 ≤ k do (∗ A[j]hat 2 Kinder ∗) (3) m ← 2 ∗ j; (4) if A[m+1] < A[m] (5) then m ← m + 1; (∗ A[m]: kleineres“ Kind ∗) ” (6) if A[m] ≥ A[j] (7) then done ← true (8) else vertausche A[m] mit A[j]; j ← m; (9) if not done then (10) m ← 2 ∗ j; (11) if m ≤ k then (12) if A[m] < A[j] (13) then vertausche A[m] mit A[j]; 1 A 3 2 B C 4 5 D F 8 6 7 E J 9 10 I H G Fertig! FG KTuEA, TU Ilmenau AuD – 13.06.2005 32 Korrektheit: Wenn vor dem Aufruf von bubbleDown(1, k) im Baum in A[1 . . k] die Heapbedingung erfüllt war, FG KTuEA, TU Ilmenau AuD – 13.06.2005 33 (Fortsetzung) außer möglicherweise in der Wurzel, d. h.: Wenn im Schleifendurchlauf für j nicht vertauscht wird, gilt auch HE(j, k), fertig. für alle i mit 2 ≤ i ≤ k gilt: Wenn A[m] mit A[j] vertauscht wird, HE(i, k) :⇔ ( 2i ≤ k 2i + 1 ≤ k dann gilt nachher HE(j, k) (wieso?). ⇒ A[i] ≤ A[2i] und In den anderen Knoten hat sich nichts geändert. ⇒ A[i] ≤ A[2i + 1] Nur HE(m, k) kann verletzt sein. dann gilt nachher die Heapbedingung HE(i, k) für 1 ≤ i ≤ k. Wegen der Zuweisung j ← m ist dies die Induktionsbehauptung für den nächsten Schleifendurchlauf. Beweis: Man zeigt durch Induktion über die Schleifendurchläufe, dass zu Beginn des Durchlaufs, in dem j die Zahl j enthält, die Heapbedingung HE(i, k) für alle i ∈ 1, . . . , k −{j} gilt. In jedem Schleifendurchlauf wird der Inhalt von j immer mindestens verdoppelt; daher terminiert die Schleife. FG KTuEA, TU Ilmenau FG KTuEA, TU Ilmenau AuD – 13.06.2005 34 AuD – 13.06.2005 35 Kosten: Angenommen, Array A[1 . . n] ist heapgeordnet. . . . von Aufruf bubbleDown(1, k): Dann können wir A[1 . . n] wie folgt fallend sortieren: O(1) + Θ(Anzahl der Schlüsselvergleiche) A[.] < A[.]“. ” Vk : Anzahl der Schlüsselvergleiche im schlechtesten Fall. Für k = n, n − 1, n − 2, . . . , 2: (∗ Das minimale Element von A[1 . . k] ist A[1]! ∗) In jedem Schleifendurchlauf 2 Vergleiche. Vertausche A[1] mit A[k]. jr : Inhalt von j in Runde r = 1, 2, 3, . . .. Verdopplung! (∗ Repariere in A[1 . . k − 1] die Heapeigenschaft: ∗) 0 j1 = 1 = 2 , jr ≥ 2 r−1 . Falls k ≥ 3: bubbleDown(1, k − 1); Vergleiche finden nur statt, falls k ≥ 2·jr ≥ 2r , d. h. r ≤ log k. Klar: Die Elemente im Array werden in steigender Reihenfolge nach A[n], A[n − 1], . . . , A[2] geschrieben; ⇒ Vk ≤ 2 · log k. das maximale Element landet schließlich in A[1]. FG KTuEA, TU Ilmenau AuD – 13.06.2005 36 Prozedur selectionPhase(1, n) (1) for k from n downto 3 do (1) vertausche A[1] mit A[k]; (1) bubbleDown(1, k − 1); (1) vertausche A[1] mit A[2]. P Kosten: 2≤k≤n(O(1) + O(2 log k )) | {z } Vk P = O(n) + O( 2≤k≤n 2 log(k − 1)) = O(n) + O(2 · n log n ) | {z } #Vergleiche FG KTuEA, TU Ilmenau AuD – 13.06.2005 37 Summation ln 2 + ... + ln(n–1), n=10 2 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 0.2 0 1 1.5 2 2.5 3 3.5 = O(n log n). ln k ≤ 2≤k≤n−1 AuD – 13.06.2005 38 4.5 5 5.5 6 6.5 7 ln x Untersumme X FG KTuEA, TU Ilmenau 4 x FG KTuEA, TU Ilmenau AuD – 13.06.2005 Z n ln x dx. 1 39 Anzahl der Vergleiche im Detail: X 2 log(k − 1) 2≤k≤n = 2 log e · X . . . und wie verwandelt man A[1 . . n] in einen Heap? Beispiel: Teil eines linksvollständigen Binärbaums, der einem Teilheap“ A[3 . . 10] entspricht: ” Teilheap ln(k − 1) 2≤k≤n n < 2 log e · Z D P A B R MN K L T E F G ln x dx 1 D = 2 log e · [x(ln x − 1)]n1 = 2 log e · (n ln n − n + 1) = 2n log n − (2 log e)(n − 1) K Also: n! ≤ (en) · (n/e)n. AuD – 13.06.2005 40 Definition Das Teilarray A[` . . k] von A[1 . . n] (1 ≤ ` ≤ k ≤ n) heißt ein Teilheap, falls innerhalb“ des Teilarrays die ” Heapeigenschaft gilt, d. h. wenn für alle i mit ` ≤ i ≤ k gilt: HE(i, k) :⇔ ( 2i ≤ k 2i + 1 ≤ k ⇒ A[i] ≤ A[2i] und ⇒ A[i] ≤ A[2i + 1] Klar: Ein Teilheap ist die disjunkte Vereinigung von heapgeordneten Bäumen. FG KTuEA, TU Ilmenau AuD – 13.06.2005 R B Folgerung aus Rechnung: ln(n!) ≤ n ln n − n + ln n + 1 FG KTuEA, TU Ilmenau A P 42 FG KTuEA, TU Ilmenau L T N M E F G AuD – 13.06.2005 41 Idee: Wenn A[` + 1 . . k] ein Teilheap ist, dann ist in dem Teilbaum T`,k mit Wurzel ` und Knoten in {`, . . . , k} die Heapbedingung höchstens in j verletzt. Kann mit einer Variante von bubbleDown Heapbedingung herstellen! Prozedur bubbleDown(`, k) (∗ Heapreparatur in T`,k ∗) (1) j ← `; done ← false; (2) while not done and 2 ∗ j + 1 ≤ k do (3) . . . FG KTuEA, TU Ilmenau AuD – 13.06.2005 43 Korrektheit: Wie bei bubbleDown(1, k). Prozedur makeHeap(1, n) (∗ Transformiert Array A[1 . . n] in Heap ∗) (1) for l from n div 2 downto 1 do (2) (∗ stelle in A[l..n] Heapbedingung her! ∗) (3) bubbleDown(l, n); Laufzeit: O(1) plus Θ(Anzahl Vergleiche). V`,k : Anzahl der Schlüsselvergleiche im schlechtesten Fall. In jedem Schleifendurchlauf 2 Vergleiche. jr : Inhalt von j in Runde r = 1, 2, 3, . . .. j1 = `. Wegen Verdopplung: jr ≥ 2r−1 · `. Korrektheit: Mit Induktion über ` = bn/2c, bn/2c − 1, . . . , 2, 1 zeige: Nach Durchlauf mit ` in l ist A[` . . n] Teilheap. r Vergleiche nur, falls k ≥ 2 · jr ≥ 2 `, d. h. r ≤ log(k/`). ⇒ V`,k ≤ 2 · log(k/`). Ind.-Anfang: Vor der ersten Runde. In A[bn/2c + 1 . . n] gibt es keine Vater-Kind-Paare; dieses Teilarray ist also auf jeden Fall Teilheap. Ind.-Schritt: Folgt aus Korrektheit von bubbleDown(l, n). FG KTuEA, TU Ilmenau AuD – 13.06.2005 44 Kosten: Anzahl der Vergleiche: X X V`,n ≤ 2 · 1≤`≤n/2 X = 2· X 45 blog(n/`)c 1≤`≤n/2 X 1 Satz X Algorithmus heapSort sortiert das Array A[1 . . n] in fallende Reihenfolge. 1 1≤j≤log n 1≤`≤n/2j X AuD – 13.06.2005 Algorithmus heapSort(A[1 . . n]) (1) makeHeap(1, n); (2) selectionPhase(1, n); 1≤`≤n/2 j : `·2j ≤n = 2· FG KTuEA, TU Ilmenau Die gesamte Laufzeit ist O(n log n). X n 1 ≤ 2· < 2n · j 2 2j 1≤j≤log n 1≤j≤log n P (∗ Geometrische Reihe: j≥1 2−j = 1. ∗) Die Gesamtzahl der Vergleiche ist kleiner als 2n log n, für genügend große n. < 2n. FG KTuEA, TU Ilmenau AuD – 13.06.2005 46 FG KTuEA, TU Ilmenau AuD – 13.06.2005 47 X Beweis: Korrektheit und Zeitbedarf folgt aus der Analyse der Teilprozeduren. 2≤k≤n ≤ log e · (ln n + Gesamtzahl der Vergleiche: P P 2n + 2≤k≤n Vk ≤ 2n + 2 · 2≤k≤n log k X log k = log e · ln k 2≤k≤n Rn 1 ln x dx) = log e · (ln n + [x(ln x − 1)]n1 ) = log e · (ln n + (n(ln n − 1) + 1)) ≤ 2n + 2n log n. = log e · ((n + 1) ln n − (n − 1)) = n log n − n log e + log n + log e. Feinere Betrachtung: Damit: 2n + X Vk ≤ 2n log n − 2n(log e − 1) + 2 log n + 2 log e. 2≤k≤n Für genügend große n ist dies < 2n log n, wie behauptet. FG KTuEA, TU Ilmenau AuD – 13.06.2005 48 FG KTuEA, TU Ilmenau AuD – 13.06.2005 49 Bemerkung 1: Wenn Sortierung in aufsteigende Reihenfolge gewünscht wird, ersetze in allen Prozeduren und Programmen Schlüsselvergleiche A[i] ≤ A[j]“ durch A[i] ≥ A[j]“ und ” ” umgekehrt. Bemerkung 4: Bei Variante 4-Way-Heapsort“ hat Knoten 1 ” die Kinder 2, 3, . . . , 7 und jeder Knoten i ≥ 2 die 4 Kinder: 4i, 4i + 1, 4i + 2, 4i + 3. Die Heapbedingung wird verallgemeinert: Die in A[1 . . n] entstehende Struktur heißt ein Max-Heap — in der Wurzel des Binärbaumes steht immer das Maximum. A[1] ≤ A[2], . . . , A[2], A[i] ≤ A[4i], A[4i + 1], A[4i + 2], A[4i + 3], i ≥ 8. Bemerkung 2: Mittlere Anzahl von Vergleichen, unter der Annahme, dass jede Anordnung der Eingabeobjekte in A[1 . . n] dieselbe Wahrscheinlichkeit 1/n! hat, ist ≈ 2n log n. Bei bubbleDown: Vertauschen mit dem kleinsten KindEintrag (Auswahl aus 4). Bemerkung 3: Variante Bottom-Up-Heapsort“ hat ” n log n + O(n) Vergleiche im mittleren Fall. Zugriff nur auf 12 log n Bereiche im Array: cache-freundlich. FG KTuEA, TU Ilmenau AuD – 13.06.2005 50 Vorteil: Baum hat nur Tiefe log4 n = 12 log n. FG KTuEA, TU Ilmenau AuD – 13.06.2005 51 Anwendungen: Priority Queues oder 1) Prozessverwaltung in Multitask-System Vorrangswarteschlangen Idee: (Daten mit) Schlüssel aus (U, <) werden eingefügt und entnommen. Beim Entnehmen wird immer der Eintrag mit dem kleinsten Schlüssel gewählt. Schlüssel = b Prioritäten“ ” — je kleiner der Schlüssel, desto höher die Priorität — Wähle stets den Eintrag mit höchster Priorität. Jeder Prozess hat einen Namen (eine ID“) und eine Priorität ” (Zahl in N). (Üblich: kleinere Zahlen bedeuten höhere Prioritäten.) Aktuell rechenbereite Prozesse befinden sich in der Prozesswarteschlange. Bei Freiwerden eines Prozessors (z.B. durch Unterbrechen eines Prozesses) wird einer der Prozesse mit höchster Priorität aus der Warteschlange entnommen und weitergeführt. Mit Heaps effizient zu realisieren! FG KTuEA, TU Ilmenau AuD – 13.06.2005 52 Anwendungen: 2) Discrete Event Simulation“ ” System von Aktionen soll auf dem Rechner simuliert werden. Jeder Aktion A ist ein Zeitpunkt tA ∈ [0, ∞) zugeordnet. Die Ausführung einer Aktion A kann neue Aktionen A0 generieren oder ausführbar machen, mit neuen Zeitpunkten tA0 > tA. Ein Schritt: Wähle diejenige noch nicht ausgeführte Aktion mit dem frühesten Ausführungszeitpunkt und führe sie aus. 3) Innerhalb von Algorithmen (Beispiele später). FG KTuEA, TU Ilmenau AuD – 13.06.2005 54 FG KTuEA, TU Ilmenau AuD – 13.06.2005 53