• Keine Ergebnisse gefunden

Grundlagen der Algorithmen und Datenstrukturen Kapitel 6

N/A
N/A
Protected

Academic year: 2022

Aktie "Grundlagen der Algorithmen und Datenstrukturen Kapitel 6"

Copied!
35
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Grundlagen der Algorithmen und Datenstrukturen

Kapitel 6

Christian Scheideler + Helmut Seidl SS 2009

(2)

Priority Queue

M: Menge von Elementen

Jedes Element e identifiziert über key(e).

Operationen:

• M.build({e0,…,en-1}): M = {e0,…,en-1};

• M.insert(Element e): M = M [ {e};

• M.min(): gib e2M mit minimalem key(e) aus

• M.deleteMin(): wie M.min(), aber zusätzlich M = Mn{e}; für e mit minimalem key(e)

(3)

Erweiterte Priority Queue

Zusätzliche Operationen:

• M.remove(Element e): M = Mn{e};

• M.decreaseKey(Element e, int ∆ ): key(e)

= key(e)-∆ ;

(bzw. M.decreaseKey(Element e), um M nach update von key(e) zu aktualisieren)

• M.merge(M´): M =M [ M´;

(4)

Priority Queue

• Priority Queue mittels unsortierter Liste:

– build({e0,…,en-1}): Zeit O(n) – insert(e): O(1)

– min, deleteMin: O(n)

• Priority Queue mittels sortierter Liste:

– build({e0,…,en-1}): Zeit O(n log n) – insert(e): O(n)

– min, deleteMin: O(1)

Bessere Struktur als Liste notwendig!

(5)

Binärer Heap

Idee: verwende binären Baum statt Liste Bewahre zwei Invarianten:

• Form-Invariante:vollst.

Binärbaum bis auf unterste Ebene

• Heap-Invariante: e1

e e

key(e1) ≤ min{key(e2),key(e3)}

(6)

Binärer Heap

Realisierung eines Binärbaums als Feld:

e0

e1 e2

e3 e4 e5 e6

e7 e8

(7)

Binärer Heap

Realisierung eines Binärbaums als Feld:

• Element [] H;

• Kinder von e in H[i]: in H[2i+1], H[2i+2]

• Form-Invariante: H[0],…,H[n-1] besetzt

• Heap-Invariante:

key(H[i]) ≤ min{key(H[2i+1]),key(H[2i+2])}

e0 e1 ee23 e3 e4 e5 e6 e7 e8

(8)

Binärer Heap

Realisierung eines Binärbaums als Feld:

insert(e):

• Form-Invariante: H[n] = e; n++;

• Heap-Invariante: vertausche e mit Vater bis key(H[(k-1)/2]) ≤ key(e) für e in H[k]

(oder e in H[0])

e0 e1 ee23 e3 e4 e5 e6 e7 e8

(9)

Insert Operation

void insert(Element e) { H[n] = e;

siftUp(n); n++;

}

void siftUp(int i) {

while (i>0 && key(H[(i-1)/2])>key(H[i])) { H[i] $ H[(i-1)/2];

i=(i-1)/2;

}

Laufzeit: O(log n)

(10)

Insert Operation - Korrektheit

3

5 8

10 9 12 15

11 18

Invariante: H[k] minimal für Teilbaum von H[k]

: Knoten, die Invariante eventuell verletzen

3

5 8

10 9 12 15

11 18 4

(11)

Insert Operation - Korrektheit

Invariante: H[k] minimal für Teilbaum von H[k]

: Knoten, die Invariante eventuell verletzen

3

5 8

10 9 12 15

11 18 4

3

5 8

10 4 12 15

11 18 9

(12)

Insert Operation - Korrektheit

Invariante: H[k] minimal für Teilbaum von H[k]

: Knoten, die Invariante eventuell verletzen

3

5 8

10 4 12 15

11 18 9

3

4 8

10 5 12 15

11 18 9

(13)

Insert Operation - Korrektheit

Invariante: H[k] minimal für Teilbaum von H[k]

: Knoten, die Invariante eventuell verletzen

3

4 8

10 5 12 15

11 18 9

3

4 8

10 5 12 15

11 18 9

(14)

Binärer Heap

deleteMin:

• Form-Invariante: n--; H[0]=H[n];

• Heap-Invariante: starte mit e in H[0].

Vertausche e mit Kind mit min Schlüssel bis H[k] ≤ min{H[2k+1],H[2k+2]} für

Position k von e (oder e in Blatt)

e0 e1 ee32 e3 e4 e5 e6 e7 e8

(15)

Binärer Heap

Element deleteMin() {

Element e = H[0]; n--; H[0] = H[n];

siftDown(0);

return e;

}

void siftDown(int i) { int m;

while (2i+1<n) {

if (2i+2>=n) m = 2i+1; // m: Pos. des min. Kindes else if (key(H[2i+1])<key(H[2i+2]) m = 2i+1;

else m = 2i+2;

if (key(H[i])<=key(H[m]) return; // Heap-Inv gilt H[i] $ H[m]; i = m;

}

(16)

Binärer Heap

Laufzeit von deleteMin: O(log n) Korrektheit von deleteMin:

• Vor deleteMin: Heap-Invariante gilt für alle i, d.h. key(H[i]) minimal für Teilbaum von H[i]

• Während deleteMin:

e in Position k: key(H[k´]) minimal für Teilbaum von H[k´] für alle k´ ungleich k (Induktion)

• Nach deleteMin: wie vor deleteMin

(17)

deleteMin Operation - Korrektheit

3

5 8

10 9 12 15

11 18

Invariante: H[k] minimal für Teilbaum von H[k]

: Knoten, die Invariante eventuell verletzen

5 8

10 9 12 15

11

18

(18)

deleteMin Operation - Korrektheit

5 8

10 9 12 15

11

Invariante: H[k] minimal für Teilbaum von H[k]

: Knoten, die Invariante eventuell verletzen

5

8

10 9 12 15

11

18 18

(19)

deleteMin Operation - Korrektheit

5

8

10 9 12 15

11

Invariante: H[k] minimal für Teilbaum von H[k]

: Knoten, die Invariante eventuell verletzen

5

8

10

9

12 15

11

18 18

(20)

Binärer Heap

build({e0,…,en-1}):

• Naive Implementierung: über n insert(e)- Operationen. Laufzeit O(n log n)

• Bessere Implementierung:

Setze H[i] = ei ; für alle i. Rufe siftDown(i) für i=(n-1)/2 runter bis 0 auf.

Aufwand (mit k=dlog ne):

O(∑1≤l<k 2l (k-l)) = O(2kj≥1 j/2j) = O(n)

(21)

Binärer Heap

Setze H[i]=ei für alle i. Rufe siftDown(i) für i = (n-1)/2 runter bis 0 auf.

Invariante: 8 j>i: H[j] min für Teilbaum von H[j]

Inv.

verletzt

(22)

Binärer Heap

Laufzeiten:

• build({e0,…,en-1}): O(n)

• insert(e): O(log n)

• min: O(1)

• deleteMin: O(log n)

Einsatz in Selection Sort (Heapsort):

Verbessert Laufzeit auf O(n log n)

(23)

Heapsort

static void heapSort(Seq<Element> s) {

Heap<Element> M = new Heap<Element>.build(s);

// Laufzeit O(n) s = ;;

while (!M.empty())

s.pushBack(M.deleteMin());

// Laufzeit O(log n) }

Gesamtlaufzeit: O(n log n)

(24)

Erweiterte Priority Queue

Zusätzliche Operationen:

• M.remove(Element e): M = Mn{e};

• M.decreaseKey(Element e, int ): key(e) = key(e)-∆ ;

• M.merge(M´): M = M [ M´;

Remove und decreaseKey in Zeit O(log n) in

Heap (wenn Position von e bekannt), aber merge ist teuer (Θ (n) Zeit)!

(25)

Binomial-Heap

Binomial-Heap basiert auf Binomial-Bäumen Binomial-Baum muss erfüllen:

• Form-Invariante (r: Rang):

• Heap-Invariante (key(Vater) ≤ key(Kinder))

r=0 r=1 r ! r+1

r

r

(26)

Binomial-Heap

Beispiel für korrekte Binomial-Bäume:

4 4

10

4

6 10

8

4

6 10

8 7

20 11

r=0 r=1 r=2 r=3

(27)

Binomial-Heap

Eigenschaften von Binomial-Bäumen:

• 2r Knoten

• maximaler Grad r (bei Wurzel)

• Wurzel weg: zerfällt in Binomial-Bäume mit Rang 0 bis r-1

r=0 r=1 r ! r+1

r

r

(28)

Binomial-Heap

Binomial-Heap:

• verkettete Liste von Binomial-Bäumen

• Pro Rang maximal 1 Binomial-Baum

• Zeiger auf Wurzel mit minimalem key

2 4

5 7

9

Zahlen: Ränge

(29)

Binomial-Heap

Beispiel eines korrekten Binomial-Heaps:

4

6 10

8 7

20 11

24

9 3

15

min-Zeiger

Binomial-Baum mit Rang r=1

(30)

Binomial-Heap

Merge von Binomial-Heaps H1 und H2:

2

5 7

2 3

5

4 6

H1

H2

10100100

+ 101100

11010000 wie Binäraddition

(31)

Beispiel einer Merge-Operation

2

5

2 3

5

7

H1

H2 Beachte beim Mergen

der Binomialbäume die Heap-Eigenschaft!

Ergebnis-Heap Zahlen geben die Ränge an

7

4 6

(32)

Binomial-Heap

Aufwand für Merge-Operation: O(log n) Bi: Binomial-Baum mit Rang i

• insert(e): Merge mit B0, Zeit O(log n)

• min: spezieller Zeiger, Zeit O(1)

• deleteMin: sei Minimum in Bi, durch Löschen von Minimum: Bi ! B0,…,Bi-1, diese zurückmergen in Binomial-Heap, Zeit O(log n)

(33)

Binomial-Heap

• decreaseKey(e,∆ ): siftUp-Operation in Binomial-Baum von e, Zeit O(log n)

• remove(e): setze key(e)=-1 und wende siftUp-Operation auf e an bis e in der

Wurzel, dann weiter wie bei deleteMin, Zeit O(log n)

(34)

Weitere Verbesserungen

Fibonacci-Heap: Verbesserung des

Binomial-Heaps, so dass amortisierte Kosten von decreaseKey O(1) sind

Keys ganzzahlig: Priority Queues bekannt, die Zeit O(1) für decreaseKey und insert und Zeit O(log log n) für deleteMin

benötigen.

(35)

Nächstes Kapitel

Thema: Suchstrukturen

Ziel: Operationen insert, remove und locate mit Laufzeit O(log n) pro Operation.

Locate(k): finde nächsten Nachfolger zu k

Referenzen

ÄHNLICHE DOKUMENTE

• liefert Garantien für die Effizienz des Algorithmus (wichtig für Robustheit) Exakte Formeln für t(n) sehr aufwendig. Einfacher:

belle T der Größe m&gt;2en mittels einer zufälligen Hashfunktion h gespeichert werden, dann ist für jedes T[i] die erwartete Länge eines Laufes in T, der T[i] enthält, O(1)..

Mergen zweier Teilfolgen mittels 3 Blöcken im internen Speicher (rote Kästen):..

Suche einen Knoten entweder mit e.key() &lt; key und linkem Nachfolger null oder mit e.key() &gt; key und rechtem Nachfolger null.. Lösche den Inhalt des

• Hashing kann verwendet werden, um Keys von n Knoten in den Bereich {0,. …,O(n)}

Dann gilt (über Induktion) für jeden Weg p, dass d[s]+c(p) ≥ d[w] für alle Knoten w. Falls sichergestellt ist, dass

• Für die Teilmengen, die das i-te Objekt nicht enthalten, ist der Wert der optimalen Lösung gleich V[i-1][w]. • Für die Teilmengen, die Objekt i enthalten, ist der Wert

Problem: Verwaltung freier Blöcke in einem gege- benen Adressraum {0,…,m-1} zur effizienten Allokation und