Musterlösung 9 - Cadmo

Werbung
ETH Zürich
Institut für Theoretische Informatik
Prof. Dr. Angelika Steger
Ralph Keusch, Florian Meier
HS 2016
Algorithmen und Komplexität
Lösungsvorschlag zu Übungsblatt 9
Lösungsvorschlag zu Aufgabe 1
Unsere Implementation verwendet zwei Stacks S1 und S2 . Für die Queue implementieren wir
die Operationen E NQUEUE ( x ) und D EQUEUE () wie folgt:
Algorithm 1 E NQUEUE ( x )
S1 .P USH ( x )
Algorithm 2 D EQUEUE ()
if S2 .isEmpty then
while not S1 .isEmpty do
S2 .P USH (S1 .P OP )
end while
end if
return S2 .P OP ()
Korrektheit: Wir zeigen, dass D EQUEUE () immer jenes Objekt y zurückgibt, welches unter allen
Objekten in der Queue als erstes mit E NQUEUE (y) eingefügt wurde. Das ist so, da das oberste
Objekt in S2 immer dieses y ist und der Algorithmus immer das oberste Objekt aus S2 zurückgibt.
Amortisierte Laufzeit: Wir definieren die Potentialfunktion φ(i ) und die Funktion t(i ) wie folgt:
φ(i ) := 2 · (Anzahl Objekte in S1 nach den ersten i Operationen)
t(i ) := Zeit, die während den ersten i Operationen aufgewendet wurde.
Wir nehmen an, dass die Operationen P OP und P USH jeweils nur einen Zeitschritt brauchen.
Offensichtlich gilt φ(0) = t(0) = 0 und φ(i ) ist immer positiv. Wir zeigen per Induktion über
i, dass t(i ) + φ(i ) ≤ 3i. (Dies ergibt die obere Schranke t(i ) ≤ t(i ) + φ(i ) ≤ 3i, da φ(i ) ≥ 0.)
Die Induktionsverankerung i = 0 ist trivial. Die Induktionshypothese ist t(i − 1) + φ(i − 1) ≤
3(i − 1) = 3i − 3. Falls nun die die i-te Operation E NQUEUE ist, finden wir
t ( i ) + φ ( i ) = t ( i − 1) + 1 + φ ( i − 1) + 2
= t(i − 1) + φ(i − 1) + 3 ≤ 3i − 3 + 3 = 3i.
Falls die i-te Operation D EQUEUE ist, unterscheiden wir, ob S2 leer ist oder nicht. Wenn S2 nicht
leer ist, ergibt sich
t ( i ) + φ ( i ) = t ( i − 1) + 1 + φ ( i − 1)
= t(i − 1) + φ(i − 1) + 1 ≤ 3i − 3 + 1 < 3i.
Falls S2 leer ist, müssen für jedes Objekt in S1 genau 2 Operationen (ein P OP von S1 und ein
P USH auf S2 ) ausgeführt werden. Am Ende wird ein zusätzliches P OP auf S2 aufgerufen. Gemäss
Definition von φ ist die Anzahl benötigter Operationen genau φ(i − 1) + 1 und folglich gilt
t ( i ) + φ ( i ) = t ( i − 1) + φ ( i − 1) + 1 + 0
≤ 3i − 3 + 1 + 0 < 3i.
1
Lösungsvorschlag zu Aufgabe 2
Wir nehmen an, dass sich die k Operationen aufteilen in eine erste Phase von k1 MakeNewSet- oder
Union-Operationen und eine zweite Phase von k2 = k − k1 Find-Operationen. Da die MakeNewSetund Union-Operationen jeweils in konstanter Zeit O(1) ausführbar sind, sind die Gesamtkosten
der ersten Phase O(k1 ).
Um die Laufzeit der zweiten Phase zu berechnen, definieren wir die Potentialfunktion φ( j) als die
Anzahl der Knoten, die nach insgesamt j Operationen von ihrer Wurzel mindestens Abstand 2
haben. Während der ersten Phase können wir höchstens k1 viele Knoten in die Struktur einfügen,
damit gilt sicher φ(k1 ) ≤ k1 .
Wenn nun mit der i-ten Find-Operation ein Knoten der Tiefe mi aufgerufen wird, so verursacht
das Zurücklaufen zur Wurzel (und die Path-Compression) Kosten Cmi für eine geeignet gewählte Konstante C. Da wir aber gleichzeitig Path-Compression durchführen, d.h. die mi − 1 Knoten,
die wir auf dem Weg zur Wurzel besuchen, direkt an die Wurzel hängen, verringert sich gleichzeitig das Potential um mi − 1. Wir haben während der zweiten Phase keine anderen Operationen,
somit verringert sich das Potential während der zweiten Phase insgesamt um ∑ik=2 1 (mi − 1).
Nun stellen wir aber fest, das per Definition φ( j) ≥ 0 für alle j gilt. Deshalb gilt insbesondere
k2
k2
i =1
i =1
0 ≤ φ ( k ) = φ ( k 1 ) − ∑ ( m i − 1) ≤ k 1 − ∑ ( m i − 1).
Darus folgt dann
k2
∑ ( m i − 1) ≤ k 1 .
i =1
Die Gesamtkosten betragen deshalb höchstens
k2
O(k1 ) + ∑ Cmi = O(k1 ) + C
i =1
k2
∑ ( m i − 1) + k 2
!
≤ O(k1 ) + C (k1 + k2 ) = O(k) .
i =1
Lösungsvorschlag zu Aufgabe 3
Für den Schlüssel k werden der Reihe nach die Speicherplätze h(k, 0), h(k, 1), h(k, 2), . . . betrachtet, und k wird im ersten freien Speicherplatz abgespeichert. Die Position, an der im i + 1-ten
Versuch nachgeschaut wird, ist für die verwendete Hash-Funktion
p(i ) = h(k, i ) = (h1 (k ) + ih2 (k ))
mod m.
Wir stellen zunächst fest, dass p(m) = p(0), denn p(m) = h1 (k) + mh2 (k ) mod m = h1 (k).
Abhängig von h2 (k) und m werden wir aber bereits früher wieder am Platz p(0) landen. Wir
überlegen uns, für welches j > 0 das zum ersten Mal passiert.
Da d der grösste gemeinsame Teiler von h2 (k ) und m ist, existieren teilerfremde natürliche Zahlen
α, β mit h2 (k) = αd und m = βd. Wegen
p( β) = (h1 (k) + βh2 (k ))
mod m
= (h1 (k) + βαd) mod m
= (h1 (k) + αm) mod m
= (h1 (k)) mod m
= p (0)
2
sind wir bereits nach β = m/d Schritten wieder am Ausgangsort und schauen danach nur noch
Speicherplätze an, die wir vorher bereits betrachtet haben. Da α und β teilerfremd sind, folgt
ähnlich für 0 < j < β, dass
p( j) = (h1 (k ) + jαd)
mod m
= (h1 (k) + ( jα/β) m) mod m
| {z }
6 ∈N
6 = p (0).
Wir kommen also genau nach β = m/d Schritten wieder am Ausgangspunkt an, und dabei wird
genau ein d-tel der m Speicherplätze betrachtet.
3
Herunterladen