Powerpoint

Werbung
GIN2 – 3. Vorlesung, SS04
Prof. Dr. Wolfram Conen
8.4.2004
Rund um Dijkstra:
- Heap-Implementierung mit Arrays
- Bottom-Up-Heaps
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
1
Heap-Implementierung mit Arrays
• Zur Erinnerung: Was ist ein Heap (=Haufen)?
Das ist ein partiell-geordneter Baum:
Definition: Ein partiell-geordneter (binärer) Baum ist ein
knotenmarkierter binärer Baum T, in dem für jeden Teilbaum T´ mit
Wurzel w gilt:
8 y 2 T´: Wert(w) · Wert(y)
[Das werden wir auch Min-Heap oder ·-Heap nennen.
In Max-Heaps bzw. ¸-Heap gilt Wert(w) ¸ Wert(y)]
• Ein Heap kann Priority-Queues unmittelbar implementieren!
• Aber wie implementiert man einen Heap?
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
2
Partiell-geordneter Baum
(Schlüssel-)Werte: 4 6 6 7 10 10 12 13 13 19
4
6
10
12
13
6
19
13
10
7
Hier unser Heap aus der letzen Vorlesung als Baum...
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
3
Partiell-geordneter Baum
(Schlüssel-)Werte: 4 6 6 7 10 10 12 13 13 19
4
6
12
13
19
Idee: Kinder von
Position i sind
an Pos. 2i und Pos. 2i+1
10
6
13
10
7
Und hier als Array:
4 6 10 12 6 13 10 13 19 7
Pos. 1
09.04.2004, 12:00
2 3
4
5 6 7
(c) W. Conen, FH GE, GIN2
8 9 10
4
Heap: INSERT
• Wir betrachten links-vollständige partiell geordnete Bäume:
– alle Ebenen bis auf die letzte sind voll besetzt
– auf der letzten Ebene sitzen die Knoten soweit links wie möglich
Algorithm INSERT(Q,v)
Füge v auf der ersten freien Position
der untersten Ebene ein (wenn
voll, neue Ebene beginnen)
p à Vater(v)
Solange p existiert und
Wert(v) < Wert(p) tue
Vertausche die Werte
von p und v;
v à p; p à Vater(p)
09.04.2004, 12:00
Nun mit Array, nennen wir es H.
( Das ist immer eins mehr, als das Ende
des Arrays (also: erweitern!)
Für gerade Pos. v ist p = i/2, sonst (i1)/2 für i>1 bzw. nichts für Wurzel
( H[i].wert < H[p].wert tue
hilfÃH[i].wert; H[i].wertÃH[p].wert;
H[p].wertÃhilf;
( Genauso, Vater wie oben finden.
(c) W. Conen, FH GE, GIN2
5
Heap: INSERT
Algorithm INSERT(Q,v)
Füge v auf der ersten freien
Position der untersten Ebene
ein (wenn voll, neue Ebene
beginnen)
p à Vater(v)
Solange p existiert und Wert(v) <
Wert(p) tue
Vertausche die Werte
von p und v;
v à p; p à Vater(p)
Einfügen von 5
4 6 10 12 6 13 10 13 19 7 5
p=5(
v = 11
Wert(v) < Wert(p)? Klar! Vertauschen!
4 6 10 12 5 13 10 13 19 7 6
pNeu= 2
vNeu= pAlt= 5
vAlt
Wert(v) < Wert(p)? Klar! Vertauschen!
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
6
Heap: INSERT
Algorithm INSERT(Q,v)
Füge v auf der ersten freien
Position der untersten Ebene
ein (wenn voll, neue Ebene
beginnen)
p à Vater(v)
Solange p existiert und Wert(v) <
Wert(p) tue
Vertausche die Werte
von p und v;
v à p; p à Vater(p)
09.04.2004, 12:00
Einfügen von 5
4 5 10 12 6 13 10 13 19 7 6
vNeu= 2
vAlt= 5
pNeu=1
Wert(v) < Wert(p)? Nein! Fertig!
(c) W. Conen, FH GE, GIN2
7
Heap: INSERT
Nach dem Einfügen von 5:
4 5 10 12 6 13 10 13 19 7 6
4
Und als Baum:
5
10
12
13
09.04.2004, 12:00
6
19
(c) W. Conen, FH GE, GIN2
7
13
10
6
8
Heap: INSERT
Oder „andersherum“:
4 5 10 12 6 13 10 13 19 7 6
13
19 7
12
6
6
13
5
10
10
4
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
9
Heap: INSERT
Oder „andersherum“ und etwas verzerrt:
4 5 10 12 6 13 10 13 19 7 6
13 19 7
12 6
5
6
13 10
10
4
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
10
Heap mit Array
• DELETE MIN völlig analog
• Kleines Randproblem: dynamisch wachsende
Arrays
– in manchen Programmiersprachen kein Problem
– Oft weiß man auch die Anzahl Objekte vorab und will
diese „nur“ sortieren (oder sortiert ausgeben, wie
beim Dijkstra)
• Initiales Einfügen aller Elemente per Insert ist
dann nicht sehr effizient, soll heißen: es geht
besser!
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
11
Heap mit Array: Aufbau
• Annahme: Wir kennen n vorab.
• Dann können wir alle Blattpositionen füllen,
ohne Vergleiche/Tauschoperationen ausführen
zu müssen!
• Warum? Das kann die partielle Ordnung nicht
verletzen!
• Wie geht das? Wir füllen das Array „von hinten
nach vorn“ und beginnen mit dem Einfügen per
INSERT erst ab Position (n DIV 2) (für n=10 also
Position 5)
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
12
Heap mit Array: Aufbau
• Naives Einfügen-von-vorn (mit INSERT) kostet
log1 + log 2 + ... + log n = (n log n)
• Jetzt haben wir Kosten für das Füllen von O(n):
– Sei a ein Array mit n Elementen.
– Zahl der Vergleiche, um eine partielle Ordnung zu erzeugen, ist
höchstens 2mal so groß, wie die Summe der Entfernungen aller
Knoten bis zur Blattebene! (Jeder Knoten sinkt von ganz oben
bis ganz unten)
– Die Summe dieser Abstände übersteigt die Zahl n NICHT:
– Etwas die Hälfte der Knoten sind Blätter, etwa 1/4 hat den
Abstand 1, etwa 1/8 den Abstand 2 usw.
– Beispiel: n = 31 (Tiefe 4, also 5 Schichten, vollbesetzt)
– Abstandssumme: 26, allgemein für vollständige Binärbäume der
Tiefe k (mit n = 2k+1 – 1 Knoten): n - k -1 (best case)
– Beispiel: n=32 (also Tiefe 5, Schicht 6 hat nur einen Knoten!)
– Abstandssumme: 31, allmein mit n = 2k+1 n-1 (worst case)
– Abstandssumme also insgesamt immer kleiner als n.
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
13
Heap „verkehrt“
• „Normale“ Heapanwendung: Heapsort
• Ohne weiteren nennenswerten Platz zu beanspruchen,
wollen wir „in situ“ (also direkt „am Ort“) sortieren.
• Das geht leichter, wenn wir einen Heap bauen, der eine
„umgekehrte“ partielle Ordnungsbedingung erfüllt: die
Wurzel ist größergleich als die Söhne (also ein ¸-Heap)
• Dann wenden wir ein DELETE MAX an und tauschen die
Wurzel (n-1)-mal gegen das letzte Element des Heaps
(und verkürzen diesen dann „von hinten“ und sammeln
so dahinter die geordneten Elemente ein! (s. Applet))
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
14
Heapsort improved
• „Normaler“ Heapsort (wie gerade beschrieben) hat
Worst- und average-case-Kosten von 2n log n + O(n)
• Zur Erinnerung: Quicksort im average-case:
1,386 n log n + O(n), worst-case: O(n2)
• Aber Heap-Sort kann es noch besser!
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
15
Bottom-Up Heapsort
• Bisher haben wir beim Einsinken gleich Ordnung geschaffen: Der
kleinere Sohn wurde ausgewählt und zur neuen Wurzel gemacht.
Das sind 2 Vergleiche: Söhne miteinander, Wurzel gegen kleineren
(bei Min-Heap) bzw. größeren Sohn (bei Max-Heap).
• Jetzt stellen wir uns vor, wir hätten beispielsweise einen Min-Heap
bis zum Element a[2] bereits gefüllt und organisiert und fügen nun
die Wurzel a[1] hinzu.
• Jetzt suchen wir zunächst eine „virtuellen“ Einsinkepfad bis ganz
nach unten (indem wir nur zwischen den Söhnen vergleichen und in
Richtung des kleineren Sohn weitergehen)...
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
16
Bottom-Up Heapsort
• ... und folgen dann dem eben beschrittenen Pfad solange
wieder nach oben, bis wir den Wert von a[1] an die Stelle
des momentan betrachteten Elements q schreiben können
(dort ist erstmals a[1] > q).
• Dann lassen wir den Wert des momentan betrachteten
Elements und alle anderen Werte auf die Position ihrer
Väter rutschen (die Wurzel ist ja gerade leer, die wird zuletzt
gefüllt, dann stoppen wir natürlich)
Auf den nächsten Slides findet sich ein Beispiel!
[Bottom-Up-Heapsort ist eine Idee von Prof. Wegener, U DO]
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
17
Bottom-Up Heapsort: Down-Phase
·-Heap, Wurzel
mit Wert 10
wird einsortiert.
12
4
6
13
Min?
12 Min?
11
19
Min?
09.04.2004, 12:00
Min?
17
15
17
13
10
12
13
20
11
16
17
11
: „Virtueller“ Einfügepfad
(c) W. Conen, FH GE, GIN2
18
Bottom-Up Heapsort: Up-Phase (1)
·-Heap, Wurzel
mit Wert 10
wird einsortiert.
12
4
10
6
12
13
15
12 > 11?
19
17
17
12
13
20
11
16
17
11
13 <12?
: Suche nach Einfügepunkt
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
19
Bottom-Up Heapsort: Up-Phase (2)
·-Heap, Wurzel
mit Wert 10
wird einsortiert.
12
12
4
4
6
10
11
6
12
13
15
12
11
19
17
17
12
13
20
11
16
17
11
13
: Ringtausch
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
20
Bottom-Up Heapsort: Performance
• Geht der Ringtausch bis zur Tiefe t (t · log n), erfordert das
log n + (log n – t) = 2 log n – t Vergleiche.
• Gerade haben wir 4 + 2 Vergleiche benötigt (die grünen Ovale)!
„Normaler Heapsort“ hätte 8 Vergleiche benötigt (warum?)
• Das benötigt im average case („Durchschnittsfall“) sehr nahe an
1*n*log n + O(n) – und besser geht es auch theoretisch für
Sortierverfahren mit paarweisen Schlüsselvergleichen kaum!
•
In Experimenten war Bottom-Up-Heapsort etwa ab n > 400 besser, als
Quicksort und ab n > 16000 besser, als Clever-Quicksort – bei Quicksort
sind die Konstanten im Faktor O(n) also günstiger, so dass er für kleine
n, trotz der schlechteren Konstante vorne, besser ist.
• Für größere n ist aber Bottom-Up-Heapsort besser (mit sich
vergrößerndem Vorsprung)!
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
21
Literatur
• Allgemein zur Algorithmik z.B.:
– Güting, Dieker: Datenstrukturen und Algorithmen, Teubner, 2. Aufl.,
2003 (krumme Grafiken und nicht sehr übersichtlich gesetzt, sonst sehr
nett, Reihenfolge nicht immer glücklich gewählt – vom Problem zur
Datenstruktur ist meist besser als umgekehrt, aber insgesamt les- und
brauchbar)
– Uwe Schöning: Algorithmik, Spektrum, 2001 (runder, tiefer, aber auch
knapp und nicht leicht)
• Speziell zu Heaps (für angehende Heap-Fans) z.B.
– Stefan Edelkamps (Juniorprof. an der Uni DO) Diplomarbeit: WeakHeapsort: Ein schnelles Sortierverfahren
– ... und jede Menge Forschungspapiere, z.B. On the Performance of
Weak-Heapsort (Edelkamp, Wegener, 1999) etc.
(das brauchen sie natürlich nicht zu lesen, aber hier finden Sie
Startpunkte, wenn sie ein „Sortier“-Spezialist werden wollen ;-)
09.04.2004, 12:00
(c) W. Conen, FH GE, GIN2
22
Herunterladen