6 Halde (Heap) Die Halde ist eine lineares Feld, welches die sogenannte Haldenbedingung: Haldenbedinung erfüllt: A[i]≥ max {A[2i], A[2i + 1]}, ∀i = 1, 2, . . . Direkt aus der Denition ergibt sich, dass n 2 . A[1] das Maximum des linearen Feldes ist. Beispiel einer Halde: Die Halde lässt sich auch als binärer Baum darstellen. Mit den Funktionen LINKS(i) und RECHTS(i) kann auf den linken bzw. rech- ten Sohn des i-ten Elements in der Baumstruktur zugegrien werden, analog mit VATER(i) auf den Vorgänger. LINKS (i) 1: RETURN 2i RECHTS(i) 1: RETURN 2i + 1 VATER (i) 1: RETURN 2i Wichtige Beobachtungen: • Das Maximum sitzt in der Wurzel des Baums • In jedem Knoten ist die Haldenbedingung erfüllt • Die Maximale Tiefe des Baums ist • In einem Teilbaum sind alle darunter liegenden Knoten kleiner oder maximal gleich groÿ. 1 blog nc Beweis für die Höhe des Haldenbaums: des Niveau bis auf das letzte voll (es gibt 2i In jedem Haldenbaum ist je- Elemente der Höhe i), das letzte Niveau enthält mindestens 1 Element. Für die Anzahl der Elemente in einem Haldenbaum der Höhe h gilt also n ≥ 1 + 2 + 4 + . . . + 2h−1 + 1 = h−1 X 2i + 1 = (2h − 1) + 1 = 2h , i=0 Für die Höhe 6.1 h gilt daher h ≤ bldnc (h ganzzahlig). Verhalden (Heapify) Verhalden ist der zentrale Prozess für alle Anwendungen der Halde. Er dient zur Aufrechterhaltung der Haldenbedingung. Der Algorithmus nimmt den Index des zu verhaldenden Elementes, Teilbäume, die die Söhne von i i, als Input. Es wird angenommen, dass die 2 als Wurzel haben, gültige Halden sind, aber das Element A[i] verletzt die Haldenbedingung möglicherweise, ist also nicht unbedingt das Maximum in seinem Teilbaum. Der Verhalde-Algorithmus lässt das Element A[i] durch eine Reihe von Vertauschungen nach unten sickern (es wird immer mit dem gröÿeren der beiden Söhne vertauscht), bis es an einer Stelle steht, wo die Haldenbedingung wieder gilt. VERHALDE (A,i) 1: l←LINKS(i), r←RECHTS(i) 2: index ← i 3: IF l≤n AND A[l]>A[i] THEN index←l 4: IF r≤n AND A[r]>A[index] THEN index←r 5: IF i6=index THEN 6: VERTAUSCHE (A[i], A[index]) 7: VERHALDE (A,index) Analyse: Der rekursive Aufruf erfolgt auf einem Teilbaum, der einen der beiden i als Wurzel hat. Dieser Teilbaum hat maximal halb so viele Elemente i. Die Rekursiongleichung lautet daher T (n) ≤ O(1) + T ( n2 ). Die Lösung ist T (n) = O(log n) (mit n als Gröÿe der Halde = Söhne von wie der Teilbaum mit Wurzel Länge des linaren Feldes). : n T (n) ≤ O(1) + T ( ) h 2 n i ≤ O(1) + O(1) + T ( ) 4 n = 2 · O(1) + T ( ) 4 n ≤ 3 · O(1) + T ( ) 8 n ≤ k · O(1) + T ( k ) 2 = ldn · O(1) + O(1) = O(log n) 2 Diese Schranke folgt auch aus der Beobachtung, dass maximal die Höhe des Haldenbaums, 6.2 h ≤ bldnc, durchlaufen wird. Aufbau einer Halde Eine Halde kann aus einem beliebigen linearen Feld A aufgebaut werden, indem die einzelnen Elemente nacheinander verhaldet werden. Da Verhalden jedoch nur auf Elementen funktioniert, deren Teilbäume bereits Halden sind, muss damit von hinten begonnen werden. Die Blätter des Haldenbaumes (die letzten n 2 Elemente) sind bereits triviale Halden, müssen also nicht verhaldet werden. BAUE_HALDE (A) 1: FOR i←n/2 DOWNTO 1 2: VERHALDE (A,i) n 2 -mal durchgeführt. D.h. T (n) = O(n·log n). Bei genauerer Betrachtung sieht man aber, dass eben nicht alle Elemente durch Analyse: Das Verhalden wird die ganze Baumhöhe durch verhaldet werden müssen. Die Schranke O(n · log n) ist nicht scharf. Ein genauerer Ansatz ergibt sich aus der Beobachtung, dass es in einer Halde n ≤ d h+1 e Elemente gibt, die mit Höhe h verhaldet werden Pbldnc h Pbldnc2 n ) = O(n) . müssen: T (n) ≤ h=0 2h P h=0 d 2h+1 eO(h) = O(n ∞ h (Die Summe kann durch eine unendliche Summe h=0 2h = 2 abgeschätzt n mit Elementen werden.) Damit kann eine Halde in linearer Zeit aus einem linearen Feld gebaut werden. 6.3 Sortieren mit Halden (Heap Sort) Mit Hilfe des VERHALDE -Algorithmus kann man auch einen Sortieralgoritmus konstruieren. Dieser nutzt die Eigenschaft der Halde aus, dass das Maximum immer an erster Stelle steht und in O(1) Zeit bestimmt werden kann. In jedem Schritt wird das Maximum mit dem letzten Element der Halde vertauscht, die Halde um 1 verkleinert, und das neue Element verhaldet. HEAP_SORT(A) 1: BAUE_HALDE(A) 2: FOR i ← n DOWNTO 2 DO 3: VERTAUSCHE (A[1],A[i]) 4: n ← n-1 5: VERHALDE (A,1) O(n), die von VERHALDE O(log n). Die T (n) = O(n) + (n − 1) · O(log n) = O(n log n). Der Die Laufzeit von BAUE_HALDE ist Laufzeit beträgt daher Algorithmus arbeitet in-place. 3 6.4 Wartschlange (Priority Queue) Eine weitere Anwendung dieser Datenstruktur ist die Warteschlange mit Prioritäten: Eine Warteschlange liegt vor, wenn folgende drei Operationen durchgeführt werden können: • EINFUEGEN (A,x) • MAX (A) • ENTFERNE_MAX (A) Diese Funktionen können mit Hilfe einer Halde sehr einfach umgesetzt werden: MAXIMUM (A) 1: RETURN A[1] ENTFERNE_MAX (A) 1: A[1] ← A[n] 2: n ← n-1 3: VERHALDE (A,1) EINFUEGEN (A,x) 1: n←n+1 , A[n]←x , i←n 2: WHILE i>1 AND A[i]>A[VATER(i)] DO 3: VERTAUSCHE (A[i],A[VATER(i)]) 4: i←Vater(i) Die Laufzeiten betragen für MAXIMUM, ENTFERNE_MAX und EINFUEGEN respektiv O(1), O(log n) und O(log n). Die Funktionen MAXIMUM und ENTFERNE_MAX nutzen aus, dass das Maximum in A[1] steht. Beim EINFUEGEN wird das neue Element ans Ende der Halde gesetzt und soweit nach oben geschoben, bis die Haldenbedingung erfüllt ist. Mittels EINFUEGEN kann eine Halde natürlich auch aufgebaut werden. Diese Variante ist jedoch inezient. BAUE_HALDE_LANGSAM(A) 1: N ← 1 2: FOR i=2 TO n DO 3: EINFUEGEN (A,A[i]) Die Laufzeit beträgt n X T (n) = O ! ldi = O(n log n). i=2 | {z } <(n−1)·ldn 4 Diese asymptotische Schranke ist schon scharf, da n X i=2 n X ldi > i= n 2 Die Laufzeit ist also mit das eine Halde in ldi > n n n n ld = ldn − = Ω(n log n). 2 2 2 2 T (n) = Θ(n log n) deutlich langsamer als BAUE_HALDE, linearer Zeit bilden kann. 5