Algorithmen und Datenstrukturen

Werbung
Was bisher geschah
ADT Menge mit Operationen:
I
Suche nach einem Element
I
Einfügen eines Elementes
I
Löschen eines Elementes
Realisierung durch verschiedene Datenstrukturen:
I
lineare Datenstrukturen:
Array, Liste, Hashtabelle
I
hierarchische Datenstrukturen:
Suchbäume, balancierte Suchbäume
Datenstrukturen mit Zugriff nur auf ein spezielles Element:
Stack, Queue mit
1. Ansehen (top, first)
2. Entfernen (pop, dequeue)
3. Einfügen einen Elementes (push, enqueue)
172
Priority-Queues
(Vorrang-Warteschlange)
Idee:
I
Modellierung von Prioritäten, z.B. Dringlichkeit
I
Datenstruktur zur Verwaltung von Paaren
(Schlüssel, Element)
I
Schlüssel repräsentieren Priorität
I
oft Rangfolge: kleiner Schlüssel = hohe Priorität
I
Zugriff nur auf ein Element mit minimalem Schlüssel
(maximale Priorität)
173
Beispiele
I
Notfallaufnahme
Prioritäten:
lebensbedrohliche (1), schwere (2), leichte (3)
Verletzungen
I
Betriebssysteme: Scheduling von Prozessen
I
kürzeste Wege in Graphen (Dijkstra)
I
Expansionsreihenfolge der Knoten in Spielbäumen
174
ADT Priority-Queue
Menge (E, ≤) von Schlüsseln (Prioritäten) mit einer totalen Ordnung
Sorten: Bool, E, PQhEi
Signatur:
EmptyPQ :
isEmpty :
PQhEi →
add :
PQhEi × E →
getmin :
PQhEi →
deletemin :
PQhEi →
PQhEi
Bool
PQhEi
E
PQhEi
Axiome (Ausschnitt) jeweils ∀p, q ∈ PQhEi ∀e, f ∈ E :

isEmpty(emptyPQ) = t, isEmpty(add(p, e)) = f,




 (isEmpty(p) ∨ e < getmin(p)) ↔ getmin(add(p, e)) = e,
(isEmpty(p) ∨ e < getmin(p)) ↔ deletemin(add(p, e)) = p,
Φ=


e
> getmin(p) → getmin(add(p, e)) = getmin(p),



e > getmin(p) → deletemin(add(p, e)) = add(deletemin(p), e)











(+ Axiome der Booleschen Algebra)
nur für Spezifikationen:
Inhalt(p) = Menge aller Schlüssel in p
175
Wiederholung: Stack, Queue
Datenstruktur (DS) mit get / remove nur für spezielles Element:
Sorten: Bool, E, DShEi
Signatur:
EmptyDS :
isEmpty :
DShEi →
add :
DShEi × E →
get0 :
DShEi →
DShEi →
remove0 :
DShEi
Bool
DShEi
E
DShEi
Spezialfälle:
Stack mit anderen Namen für Operationen:
add 7→ push, remove’ 7→ pop, get’ 7→ top
spezielles = „neuestes“ enthaltenes Element
Queue mit anderen Namen für Operationen:
add 7→ enqueue, remove’ 7→ dequeue, get’ 7→ front
spezielles = „ältestes“ enthaltenes Element
Priority-Queue mit anderen Namen für Operationen:
add 7→ add, remove’ 7→ deletemin, get’ 7→ getmin
spezielles = minimales enthaltenes Element
176
Stack und Queue als Priority-Queues
Queue Priorität jedes neu in die PQ eingefügten
Elementes kleiner (Schlüssel größer) als
Maximum aller schon in der PQ enthaltenen
Elemente
(Einfügen aufsteigend geordneter Schlüsselfolge)
Stack Priorität jedes neu in die PQ eingefügten
Elementes größer (Schlüssel kleiner) als
Maximum aller schon in der PQ enthaltenen
Elemente
(Einfügen absteigend geordneter Schlüsselfolge)
177
Sortieren mit Priority-Queue
Wiederholung: Spezifikation des Sortier-Problemes
V: Eingabe (x1 , x2 , . . . , xn ) mit ∀i ∈ {1, . . . , n} : xi ∈
N
N: Ausgabe (y1 , y2 , . . . , yn ) ist
1. y1 < y2 ≤ · · · < yn+1 (aufsteigend geordnet) und
2. eine Permutation (Umordnung) der Eingabe
(x1 , x2 , . . . , xn )
Algorithmus : PQ-Sort
Eingabe : x = (x1 , . . . , xn )
Ausgabe : y = (y1 , . . . , yn )
p ← emptyPQ
für jedes i ← 1, . . . , n :
p ← add(p, xi )
für jedes i ← 1, . . . , n :
yi ← getmin(p)
p ← deletemin(p)
Laufzeit: n-mal add + n-mal (getmin + deletemin)
abhängig von Realisierung der PQ
178
PQ – Realisierung durch Folgen
unsortierte Folge:
I
add: (als erstes / letztes Element)
O(1) bis O(n) (Liste, Array)
I
getmin, deletemin: (Minimum-Suche) O(n)
I
PQ-Sortierverfahren: O(n2 )
sortierte Folge:
I
add: (aufsteigend) sortiertes Einfügen in O(n)
I
getmin: (erstes / letztes Element) O(1)
I
deletemin: (erstes / letztes Element)
O(1) bis O(n) (Liste, Array)
I
PQ-Sortierverfahren: O(n2 )
179
PQ – Realisierung durch Bäume
Binäre Suchbäume:
Laufzeiten: Tiefe des Baumes
I
add: sortiertes Einfügen in O(log n) bis O(n)
I
getmin, deletemin: (linker äußerer Knoten)
O(log n) bis O(n)
I
PQ-Sortierverfahren: O(n log n) bis O(n2 )
Suchbäume mit geeigneter Balance-Eigenschaft
(z.B. AVL-Bäume, B-Bäume, Rot-Schwarz-Bäume):
Laufzeiten: Tiefe des Baumes
I
add: sortiertes Einfügen in O(log n)
I
getmin, deletemin: O(log n)
I
PQ-Sortierverfahren: O(n log n)
180
Binäre Heaps
Ein Binärbaum t erfüllt die Heap-Eigenschaft gdw.
t erfüllt beide folgende Eigenschaften
Struktureigenschaft (Balance): t hat Heap-Form, d.h.
1. vollständig balancierter Binärbaum der Tiefe
blog(size(t))c und restliche Knoten in
2. Blatt-Schicht „von links vollständig“ belegt
Ordnungseigenschaft: t ist Heap-geordnet, d.h.
in jedem Knoten
Branch(x, Branch(y , l, r ), Branch(z, s, t)) in t gilt:
x ≤ y und x ≤ z
Auf jedem Pfad von der Wurzel zu einem Blatt eines
Heap-geordneten Baumes sind die Schlüssel aufsteigend
geordnet.
181
Binärer Heap – add
Spezifikation add
V: Eingabe binärer Heap t, Schlüssel k
N: Ausgabe binärer Heap s mit Inhalt(s) = Inhalt(t) ∪ {k }
Idee zum Einfügen eines Schlüssels k in t (in zwei Schritten):
1. Neuen Knoten mit Schlüssel k auf der ersten freien
Position im Heap t (Blattebene) einfügen
(ggf. neue Blattebene beginnen)
Heap-Ordnung ist danach evtl. verletzt
2. rekursiv entlang des Pfades vom neu eingefügten Knotens
zur Wurzel:
solange Schlüssel des Kindes größer als Schlüssel des
Vaters: Schlüssel austauschen (bubble)
Warum erhält diese Operation die Heap-Eigenschaft?
Laufzeit: O(log n) (Tiefe des Baumes)
182
Binärer Heap – getmin
Spezifikation getmin
V: Eingabe (nichtleerer) binären Heap t
N: Ausgabe Schlüssel m = min(Inhalt(t))
(d.h. ∀k 0 ∈ Inhalt(t) : m < k 0 )
Idee: Rückgabe des Schlüssels in der Wurzel des Heap
getmin(Branch(k , l, r )) ← k
Laufzeit: O(1)
183
Binärer Heap – deletemin
Spezifikation deletemin
V: Eingabe (nichtleerer) Heap t
N: Ausgabe binärer Heap s mit
Inhalt(s) = Inhalt(t) \ {min(Inhalt(t))}
Idee: Löschen des Wurzelknotens im Heap t in zwei Schritten:
1. Kopie des Schlüssels des „letzen“ Blattes in die Wurzel,
Löschen des letzten Blattes
Heap-Eigenschaft ist danach evtl. verletzt
2. rekursiv beginnend in der Wurzel,
solange Schlüssel des Vaters kleiner als Schlüssel eines
Kindes:
Austausch der Schlüssel von Vater und dem Kind mit dem
kleinstem Schlüssel
Warum erhält diese Operation die Heap-Eigenschaft?
Laufzeit: O(log n) (Tiefe des Baumes)
184
Heapsort
(PQ-Sort mit PQ-Realisierung als binärer Heap)
Spezifikation Sortieren (aufsteigend):
V: Eingabe (x1 , x2 , . . . , xn ) mit ∀i ∈ {1, . . . , n} : xi ∈
N
N: Ausgabe (y1 , y2 , . . . , yn ) ist
1. y1 ≤ y2 ≤ · · · ≤ yn+1 (aufsteigend geordnet) und
2. eine Permutation (Umordnung) der Eingabe
(x1 , x2 , . . . , xn )
Algorithmus : Heapsort
Eingabe : x = (x1 , . . . , xn )
Ausgabe : y = (y1 , . . . , yn )
p ← Leaf (leerer binärer Heap)
für jedes i ← 1, . . . , n :
p ← add(p, xi )
für jedes i ← 1, . . . , n :
yi ← getmin(p)
p ← deletemin(p)
Gesamtlaufzeit: O(n log n)
185
Repräsentation binärer Heaps als Arrays
Idee:
Speichern der Knoten des Heap t (Binärbaum) in Array
(x1 , . . . , xsize(t) ), wobei
I
I
x1 = Wurzel
Nachbarn jedes Knotens xi in x
I
I
Kinder: x2i , x2i+1
Vater: xbi/2c
(Zugriff in O(1))
(Zugriff in O(1))
Heapsort-Implementierung häufig mit Array-Repräsentation
(in-situ-Sortierverfahren mit Laufzeit O(n log n))
186
Herunterladen