Datenstrukturen und Algorithmen

Werbung
Datenstrukturen und Algorithmen
Musterlösung zu Hausübungsblatt 2
Daniel Warner∗
28. Mai 2007
Aufgabe 5
Nachfolgend ist der Algorithmus Merge-Sort im Pseudocode dargestellt [2].
Merge-Sort(A, p, r)
1
2
3
4
5
if p < r
then q ← b (p+r)
2 c
Merge-Sort(A,p,q)
Merge-Sort(A,q + 1,r)
Merge(A,p,q,r)
Es sei A ein beliebiges Array der Länge n = r − p + 1. Der erste rekursive Aufruf von
Merge-Sort operiert auf einem Array der Länge
p+r
c−p+1
2
p+r
=b
− p + 1c
2
r−p+1+1
=b
c
2
n+1
=b
c
2
n
= d e.
2
q−p+1 = b
Der zweite rekursive Aufruf von Merge-Sort operiert auf einem Array der Länge
n
n
n − (q − p + 1) = n − d e = b c.
2
2
∗ [email protected]
Damit ergibt sich, mit dem Wissen über die worst-case-Laufzeit von Merge, die folgende Rekurrenzgleichung für die worst-case-Laufzeit von Merge-Sort für beliebiges
n ∈ N, n > 2:
n n T (n) = T
+T
+ cn
2
2
Es gelte außerdem T (1) = 1.
Wir vermuten T (n) 6 dn log n = O(n log n) und beweisen unsere Vermutung durch
vollständige Induktion nach n. Dabei ist d ∈ R>0 eine geeignete Konstante, die erst im
Laufe des Beweises konkret bestimmt wird. Zur Induktionsvoraussetzung: Es sei n > 2 und
T (n 0 ) 6 dn 0 log n 0
gelte für alle n 0 < n. Zum Induktionsschritt:
n n T (n) = T
+T
+ cn
2
2
n
n
n
n
6 d
log
+d
log
+ cn
2
2
2
2
(I.V.)
n n n
log
+
+ cn
6d
2
2
2
n
= dn log
+ cn
2
n+1
< dn log
+ cn
2
3
6 dn log n + cn
4
(n>2)
3
= dn log + log n + cn
4
3
= dn log n + c + d log n
4
6 dn log n
Die letzte Ungleichung ist erfüllt, falls d >
c
.
log 43
Damit ist der Induktionsschritt gezeigt.
Es fehlt nun noch der Induktionsanfang: Aufgrund der Definition des O-Kalküls genügt
es den Induktionsanfang für n = 2 und n = 3 zu zeigen. Für n = 2 erhalten wir
2 2 !
T (2) = T
+T
+ 2c = 2T (1) + 2c = 2c + 2 6 2d log 2 = 2d,
2
2
und für n = 3 erhalten wir
3 3 !
+T
+ 3c = T (2) + T (1) + 3c = 5c + 3 6 3d log 3.
T (3) = T
2
2
Die beiden mit ! gekennzeichneten Ungleichungen gelten, falls d > c + 1 und d >
also setzen wir d auf das Maximum von c + 1,
5c+3
3 log 3
und
vollständig, und es gilt
c
.
log 43
5c+3
3 log 3 ,
Damit ist der Beweis
T (n) 6 dn log n = O(n log n).
Es gilt bekanntlich sogar T (n) = Θ(n log n). Um dies zu beweisen, zeigt man analog
mit der Substitutionsmethode, dass auch die untere Schranke T (n) = Ω(n log n) gilt.
2
Aufgabe 6
Wir lösen die durch
T (n) =
3T ( n
2 ) + cn,
falls n > 1
sonst
d,
definierte Rekurrenzgleichung durch Anwenden der Iterationsmethode. Dazu setzen wir
T (n) iterativ in sich selbst ein und versuchen nach einigen Iterationen eine allgemeine
Formel für die k.te Iteration aufzustellen:
1. Iteration T (n) = 3T ( n
2 ) + cn
2. Iteration
= 3 3T ( 2n2 ) + c n
2 + cn
= 32 T ( 2n2 ) + 3c n
2 +cn
n
2
3. Iteration
= 3 3T ( 23 ) + c 2n2 + 3c n
2 + cn
= 33 T ( 2n3 ) + 32 c 2n2 + 3c n
2 + cn
..
.
Nach diesen Iterationsschritten haben wir Anlass zur Behauptung, dass
T (n) = 3k T
n k−1
X
n
+
3i c i
k
2
2
i=0
für alle k ∈ N mit k 6 log n gilt.1 Wir beweisen die Korrektheit der geschlossenen Formel
für T (n) durch vollständige Induktion: Der Induktionsanfang entspricht der 1. Iteration.
Die Behauptung sei nun korrekt für k − 1 ∈ N mit k 6 log n. Dann gilt:
T (n) = 3k−1 T
(I.V.)
k−1
=3
= 3k T
= 3k T
n k−2
X
n
+
3i c i
k−1
2
2
i=0
n
n X i n
3T k + c k−1 +
3c i
2
2
2
k−2
n
n
+ 3k−1 c k−1 +
2k
2
n
+
2k
k−1
X
i=0
3i c
i=0
k−2
X
3i c
i=0
n
2i
n
2i
Damit ist auch der Induktionsschritt gezeigt, und mit dem Prinzip der vollständigen Induktion folgt die Behauptung.
Die Iteration bricht bei T (1) ab, d.h. wenn 2nk = 1 gilt. Das gilt aber genau dann, wenn
k = log n. Wir formen nun die geschlossene Formel für T (n) unter Verwendung der
1 Wir
nehmen ohne Einschränkung an, dass n eine Zweierpotenz ist.
3
endlichen geometrischen Reihe für k = log n um:
T (n) = 3k T
n k−1
X
n
+
3i c i
k
2
2
i=0
X
log(n)−1
= 3log n T (1) +
3i c
i=0
= dnlog 3 + cn
=
=
X
log(n)−1
n
2i
3 i
2
i=0
3 log n
−1
log 3
2
dn
+ cn
3
2 −1
3
nlog 2 − 1
log 3
dn
+ cn
1
2
log 3
log 32
= dn
+ 2cnn
− 2cn
= dnlog 3 + 2cn
log( 32 )+1
= dnlog 3 + 2cn
log( 32 )+log 2
= dn
log 3
+ 2cn
log 3
− 2cn
− 2cn
− 2cn
= (2c + d)nlog 3 − 2cn
= Θ(nlog2 3 )
Wir erhalten also insgesamt
T (n) = Θ(nlog2 3 ).
Wir zeigen nun die Korrektheit des Algorithmus. Es sei n = 2k . Wir führen Induktion
nach k. Der Induktionsanfang k = 0 ist klar: Der Algorithmus multipliziert zwei Bits stets
korrekt. Als Induktionsvoraussetzung nehmen wir an, dass der Algorithmus auf allen Integern der Länge 2k−1 = n
2 korrekt arbeitet. Zum Induktionsschritt: Der Algorithmus erhält
als Eingabe zwei n-Bit Integer X und Y. Diese werden in einen höherwertigen und einen
n
n
2
2
niederwertigen Teil der Länge jeweils n
2 aufgeteilt, sodass X = 2 A + B und Y = 2 C + D.
Nach Induktionsvoraussetzung werden die Produkte BD, AC und (A + B)(C + D) korrekt
berechnet. Einfaches Nachrechnen zeigt, dass
n
n
n
BD + 2 2 ((A + B)(C + D) − AC − BD) + 2n AC = (2 2 A + B)(2 2 C + D) = XY
gilt, womit auch der Induktionsschritt gezeigt ist. Damit folgt die Korrektheit des Algorithmus.
Aufgabe 7a
Wir lösen die durch
T (n)
3
6 9T ( n
3 ) + 9n ,
falls n > 1
sonst
= c,
4
definierte Rekurrenzgleichung durch Anwenden der Iterationsmethode. Dazu setzen wir
T (n) iterativ in sich selbst ein und versuchen nach einigen Iterationen eine allgemeine
Formel für die k.te Iteration aufzustellen:
3
1. Iteration T (n) 6 9T ( n
3 ) + 9n
3 + 9n3
2. Iteration
6 9 9T ( 3n2 ) + 9( n
)
3
2
= 92 T ( 3n2 ) + 933 n3 + 9n3
2
3. Iteration
6 92 9T ( 3n3 ) + 9( 3n2 )3 + 393 n3 + 9n3
3
2
= 93 T ( 3n3 ) + (393 )2 n3 + 933 n3 + 9n3
..
.
Nach diesen Iterationsschritten haben wir Anlass zur Behauptung, dass
k
n X
9i
T (n) 6 9 T k +
n3
3(i−1)
3
3
k
i=1
für alle k ∈ N mit k 6 log3 n gilt.2 Wir beweisen die Korrektheit der geschlossenen
Formel für T (n) durch vollständige Induktion: Der Induktionsanfang entspricht der 1.
Iteration. Die Behauptung sei nun korrekt für k − 1 ∈ N mit k 6 log3 n. Dann gilt:
T (n) 6 9
(I.V.)
k−1
n k−1
X 9i
n3
T k−1 +
3(i−1)
3
3
i=1
k−1
n
n 3 X 9i
6 9k−1 9T k + 9 k−1
n3
+
3
3
33(i−1)
i=1
n
n 3 k−1
X 9i
k
k
= 9 T k +9
n3
+
3
3k−1
33(i−1)
i=1
k
n X
9i
k
=9 T k +
n3
3
33(i−1)
i=1
Damit ist auch der Induktionsschritt gezeigt, und mit dem Prinzip der vollständigen Induktion folgt die Behauptung.
Die Iteration bricht bei T (1) ab, d.h. wenn 3nk = 1 gilt. Das gilt aber genau dann, wenn
k = log3 n. Wir formen nun die geschlossene Formel für T (n) unter Verwendung der
2 Wir
nehmen ohne Einschränkung an, dass n eine Dreierpotenz ist.
5
unendlichen geometrischen Reihe für k = log3 n um:
log3 n
log3 n
T (n) 6 9
T (1) +
= cnlog3 9 + 9n3
X
9i
33(i−1)
i=1
log3 n X
i=1
6 cn2 + 9n3
= cn2 +
9 i−1
33
∞ X
1 i
3
i=0
= cn2 + 9n3
n3
1
1−
1
3
27 3
n
2
= O(n3 )
Wir erhalten also insgesamt
T (n) = O(n3 ).
Aufgabe 7b
Die Laufzeit T (n) eines Algorithmus A sei gegeben durch die Rekurrenzgleichung3
2
7T ( n
2 ) + n , falls n > 1
T (n) =
1,
sonst,
und die Laufzeit S(n) eines Algorithmus B sei gegeben durch die Rekurrenzgleichung
2
aS( n
4 ) + n , falls n > 1
S(n) =
1,
sonst
mit a ∈ N.
Wir zeigen zwei unterschiedliche Herangehensweisen zur Lösung der Aufgabenstellung: Bei der ersten Variante gehen wir elementar vor, bei der zweiten Variante wenden
wir das Master-Theorem an. Es zeigt sich im Vergleich der beiden Ansätze deutlich, dass
die Verwendung des Master-Theorems einem in dieser Situation viel Arbeit abnimmt (die
dafür aber in den Beweis des Master-Theorems investiert wurde).
Bei beiden Beweisvarianten benutzen wir das folgende Lemma:
Lemma 1. Es seien s1 : N → N und s2 : N → N Funktionen, und es gelte s1 ∈ o(s2 ). Dann
gilt O(s1 ) ⊆ o(s2 ).
3 Dies
ist gerade die Rekurrenzgleichung, die sich bei der Laufzeitanalyse des Matrixmultiplikationsalgorithmus von Strassen ergibt.
6
Beweis. Nach Voraussetzung gilt
∀c 0 > 0 ∃n0 ∈ N ∀n > n0 : s1 (n) 6 c 0 s2 (n).
Es sei nun f ∈ O(s1 ) beliebig. Dann gilt
∃c1 > 0 ∃n1 ∈ N ∀n > n1 : f(n) 6 c1 s1 (n).
Es sei c > 0 beliebig. Setze c 0 =
c
c1 .
Dann gilt c 0 > 0, und es folgt
∃n0 ∈ N ∀n > n0 : c1 s1 (n) 6 c1 c 0 s2 (n) = cs2 (n).
Mit f ∈ O(s1 ) und n2 := max(n0 , n1 ) erhalten wir schließlich
∀n > n2 : f(n) 6 c1 s1 (n) 6 cs2 (n)
und damit f ∈ o(s2 ).
Anschaulich: Wenn die Funktion s1 (asymptotisch) langsamer als s2 wächst, dann wächst
jede Funktion f : N → N, die höchstens so schnell wächst wie s1 , langsamer als s2 .
Elementare Lösung
Mit der Iterationsmethode und vollständiger Induktion erhalten wir
k−1
n
X 7 i
2
T (n) = 7T
+n = 7 T k +n
2
2
4
n
2
k
i=0
für alle k 6 log2 n und
S(n) = aS
n
4
+ n2 = ak S
k−1
n
X a i
2
+
n
4k
16
i=0
für alle k 6 log4 n.
Die Iteration bricht jeweils bei T (1) ab, d.h. wenn 2nk = 1 bzw. 4nk = 1 gilt. Das gilt
aber genau dann, wenn k = log2 n bzw. k = log4 n. Unter Verwendung der endlichen
geometrischen Reihe lassen sich T (n) und S(n) (für a 6= 16) in eine geschlossene Form
umformen:
7
4
T (n) = nlog2 7 − n2 = Θ(nlog2 7 )
3
3
a
1
log4 a
2
S(n) =
n
+
a n
a − 16
1 − 16
Um die asymptotische Laufzeit des Algorithmus B zu bestimmen, unterscheiden wir
drei Fälle:
7
a<16:
Wir erhalten
S(n) = c1 nlog4 a + c2 n2
mit c1 =
a
a−16
6 0 und c2 =
1
a
1− 16
> 0. Daraus folgt
S(n) = Θ(n2 ).
Wegen limn→∞
n2
nlog2 7
= limn→∞
1
7
nlog2 4
= 0 gilt n2 ∈ o(nlog2 7 ). Mit Lemma 1 folgt
Θ(n2 ) ⊆ O(n2 )
o(nlog2 7 ),
⊆
(Lemma 1)
und wir erhalten
S(n) = o(nlog2 7 ),
d.h. S(n) wächst asymptotisch langsamer als T (n) = Θ(nlog2 7 ).4 Mit anderen Worten: Der
Algorithmus B ist asymptotisch schneller als der Algorithmus A.
Wir erhalten durch Einsetzen von a = 16 und k = log4 n in die geschlossene Form
von S(n):
a=16:
S(n) = 16log4 n + n2 log4 n = nlog4 16 + n2 log4 n = n2 + n2 log4 n = Θ(n2 log n)
Wegen limn→∞
n2 log2 n
nlog2 7
= 0 gilt n2 log2 n ∈ o(nlog2 7 ). Mit Lemma 1 folgt
Θ(n2 log n) ⊆ O(n2 log n)
⊆
o(nlog2 7 ),
(Lemma 1)
und wir erhalten
S(n) = o(nlog2 7 ),
d.h. S(n) wächst asymptotisch langsamer als T (n) = Θ(nlog2 7 ). Mit anderen Worten: Der
Algorithmus B ist asymptotisch schneller als der Algorithmus A.
a>16:
Wir erhalten
S(n) = c1 nlog4 a + c2 n2
mit c1 =
a
a−16
> 1 und c2 =
1
a
1− 16
6 0. Daraus folgt
S(n) = Θ(nlog4 a ).
Es soll nun der größte Wert von a ∈ N bestimmt werden, für den der Algorithmus B
asymptotisch schneller als der Algorithmus A ist. Mit den beiden bereits behandelten
4 Hier
fließt ein, dass stets o(f) ∩ Ω(f) = ∅ gilt.
8
Fällen wissen wir, dass a > 16 gelten muss. Weiterhin gilt
nlog4 a = o(nlog2 7 )
nlog4 a
=0
n→∞ nlog2 7
⇔ lim nlog4 a−log2 7 = 0
⇔ lim
n→∞
⇔ log4 a − log2 7 < 0
1
⇔ log2 a < log2 7
2
⇔ log2 a < 2 log2 7
⇔ log2 a < log2 72 = log2 49
⇔a < 49
Wir erhalten also, zusammen mit Lemma 1, dass O(nlog4 a ) ⊆ o(nlog2 7 ) genau dann gilt,
wenn a < 49. Somit ist der größte ganzzahlige Wert von a, für den S(n) asymptotisch
langsamer wächst als T (n) = Θ(nlog2 7 ), gerade a = 48. Mit anderen Worten: Der größte
ganzzahlige Wert von a, für den der Algorithmus B asymptotisch schneller ist als der
Algorithmus A, ist a = 48.
Die drei untersuchten Fälle a < 16, a = 16 und
a > 16 entsprechen gerade genau den drei Fällen des Master-Theorems (vgl. [2], S. 73),
das wir nun statt der Iterationsmethode anwenden, um die Rekurrenzgleichungen T (n)
und S(n) zu lösen.
Offensichtlich gilt n2 = Ω(nlog2 (7)− ) mit := log2 74 > 0. Mit dem Master-Theorem
erhalten wir sofort
T (n) = Θ(nlog2 7 ).
Verwendung des Master Theorems
n 2
2
Es gilt n2 = Ω(nlog4 (a)+ ) mit := log4 16
a > 0. Des Weiteren gilt a( 4 ) 6 cn
für fast alle n ∈ N und eine Konstante 0 < c < 1. Nach dem Master-Theorem gilt nun
a<16:
S(n) = Θ(n2 ).
Genau wie bei der elementaren Lösung begründet man nun S(n) = o(nlog2 7 ).
a=16:
Es gilt offensichtlich n2 = Θ(nlog4 a ). Mit dem Master-Theorem folgt
S(n) = Θ(n2 log n).
Genau wie bei der elementaren Lösung zeigt man nun S(n) = o(nlog2 7 ).
a>16:
a
16 >
log4 a
Es gilt n2 = Ω(nlog4 (a)− ) mit := log4
S(n) = Θ(n
0. Mit dem Master-Theorem folgt
).
Wie bei der elementaren Lösung beweist man nun, dass der größte ganzzahlige Wert von
a, für den der Algorithmus B asymptotisch schneller ist als der Algorithmus A, gerade
a = 48 ist.
9
Aufgabe 8
Wir verfolgen den folgenden rekursiven Ansatz, um n Scheiben von einem Startstapel auf
einen Zielstapel unter Zuhilfenahme eines Hilfsstapels zu bewegen:
1. Bewege die n − 1 kleinsten Scheiben vom Startstapel auf den Hilfsstapel.
2. Bewege die größte der n Scheiben vom Startstapel auf den Zielstapel.
3. Bewege die n − 1 kleinsten Scheiben vom Hilfsstapel auf den Zielstapel.
Wir gehen zunächst davon aus, dass dieser Ansatz immer eine korrekte Lösung liefert und analysieren die Komplexität. Es sei T (n) die minimale Anzahl Bewegungen, die
notwendig sind, um n Scheiben von einem Stapel auf einen anderen Stapel (unter den
vorgegebenen Regeln) zu transportieren. Dann benötigt Schritt 1 T (n − 1) Bewegungen,
Schritt 2 eine Bewegung und Schritt 3 wiederum T (n − 1) Bewegungen. Folglich können
n Scheiben in (höchstens) 2T (n − 1) + 1 Schritten bewegt werden, d.h. es gilt
T (n) 6 2T (n − 1) + 1
für n > 0. Damit sind 2T (n − 1) + 1 Bewegungen hinreichend zur Lösung; wir müssen
noch argumentieren, dass diese Anzahl Bewegungen auch notwendig ist [4]:
Irgendwann muss die größte der n Scheiben auf den Zielstapel bewegt werden. Zu
dem Zeitpunkt müssen die n − 1 kleinsten Scheiben bereits auf einen einzigen anderen
Stapel bewegt worden sein. Dies benötigt mindestens T (n − 1) Bewegungen. Wir könnten
die größte Scheibe mehr als einmal bewegen, aber nachdem wir die größte Scheibe das
letzte mal bewegt haben, müssen wir die n − 1 kleinsten Scheiben von ihrem Stapel auf die
größte Scheibe transportieren. Dies benötigt wiederum mindestens T (n − 1) Bewegungen.
Also gilt
T (n) > 2T (n − 1) + 1,
und wir erhalten insgesamt
T (n) =
2T (n − 1) + 1,
falls n > 0
0,
falls n = 0.
Mit vollständiger Induktion zeigt man leicht, dass
T (n) = 2n − 1
für alle n > 0 gilt.5
Wir geben mit diesen Vorüberlegungen nun einen Algorithmus an, der das Problem
„Türme von Hanoi“ korrekt löst:
Hanoi(n)
1
Hanoi-Recursive(n, A, B, C)
5 Interessanterweise
ist 2n − 1 gerade die n.te Mersenne’sche Zahl.
10
Hanoi-Recursive(i, start, hilf , ziel)
1
2
3
4
if i > 0
then Hanoi-Recursive(i − 1, start, ziel, hilf )
Bewege die oberste Scheibe von start nach ziel.
Hanoi-Recursive(i − 1, hilf , start, ziel)
Mit dem Vorstehenden ist die Laufzeit des Algorithmus Hanoi Θ(2n ).
Zur Korrektheit: Wir zeigen per vollständiger Induktion nach n ∈ N0 , dass der Aufruf
Hanoi-Recursive(n, a, b, c) eine korrekte Bewegungsfolge liefert, wann immer n Scheiben auf einem beliebigen Startstapel a liegen und zu einem beliebigen Zielstapel c 6= a
unter Zuhilfenahme eines Hilfsstapels b (b 6= a und b 6= c) transportiert werden sollen,
wobei auf b und c, sofern sie nicht leer sind, nur Scheiben liegen, die größer sind als die
größte der zu transportierenden n Scheiben. Für n = 0 ist die Aussage trivial und damit
der Induktionsanfang erfüllt.
Im Induktionsschritt schließen wir von n − 1 auf n > 0. Nach Induktionsvoraussetzung
bewegt der Aufruf Hanoi-Recursive(n − 1, a, c, b) die oberen n − 1 Scheiben korrekt von
a nach b, denn die Rollen von b und c als Hilfs- bzw. Zielstapel können vertauscht werden. Die größte der n zu transportierenden Scheiben wird daraufhin auf den Stapel c
transportiert, was zulässig ist, da c nach Voraussetzung entweder leer ist, oder auf c nur
Scheiben liegen, die größer sind als die größte der n zu transportierenden Scheiben. Nun
liegen auf dem Stapel a, sofern er nicht leer ist, nur Scheiben, die größer sind als die
größte der n − 1 nun zu verschiebenden Scheiben. Entsprechendes gilt für den Stapel c.
Der anschließende Aufruf Hanoi-Recursive(n − 1, b, a, c) bewegt also nach Induktionsvoraussetzung die n − 1 obersten Scheiben korrekt vom Stapel b auf den Stapel c. Damit
sind alle n Scheiben vom Startstapel a korrekt auf den Zielstapel c transportiert worden.
Es folgt unmittelbar die Korrektheit des Algorithmus Hanoi.
Die Türme von Hanoi sind ein Beispiel für ein praktisch unlösbares Problem: Die Anzahl Bewegungen, die notwendig und hinreichend ist, um n > 0 Scheiben von einem
Stapel auf einen anderen Stapel zu bewegen ist T (n) = 2n − 1; wir haben gesehen, dass
sich dieses Ergebnis nicht verbessern lässt. Diese Anzahl ist aber exponentiell in der Anzahl n der Scheiben.
Wie in Tabelle 1 ersichtlich, wird die Anzahl der Bewegungen selbst für „kleine“ n
„astronomisch“. Die in der Tabelle 1 angegebene Abschätzung für die benötigte Zeit,
ergibt sich unter der Annahme, dass ein Mönch eine Scheibe pro Sekunde verschieben
kann und bis zur Vollendung der Aufgabe ohne Unterbrechung arbeitet. Zieht man in
Betracht, dass unser Universum etwa 13,5 Milliarden Jahre alt ist, so besteht also zunächst
kein Anlass zu Weltuntergangsstimmung.
11
Anzahl Scheiben
5
10
20
30
40
60
64
Minimale Anzahl Bewegungen
31
1.023
1.048.575
1.073.741.823
1.099.511.627.775
1.152.921.504.606.846.975
18.446.744.073.709.551.615
Benötigte Zeit
31 Sekunden
17 Minuten
12 Tage
34 Jahre
348 Jahrhunderte
36 Milliarden Jahre
584 Milliarden Jahre
Tabelle 1: Praktische Unlösbarkeit der Türme von Hanoi [7]
Aufgabe 9
Definitionen und Problemstellung
Definition 2. Es seien p1 , p2 ∈ Rd Punkte. Wir sagen, dass der Punkt p1 = (x1 , . . . , xd )
den Punkt p2 = (x10 , . . . , xd0 ) dominiert, falls xk > xk0 für alle k ∈ { 1, 2, . . . , d }. Im Falle des
R2 heißt das für p1 = (x1 , y1 ) und p2 = (x2 , y2 ), dass x1 > x2 und y1 > y2 gilt.
Es sei P ⊆ Rd eine Menge von Punkten. Ein Punkt m ∈ P heißt maximal (in P), falls
er von keinem anderen Punkt aus P dominiert wird. Wir nennen die Menge M ⊆ P der
maximalen Punkten in P die Pareto-Menge von P.
Abbildung 1 verdeutlicht die Begriffe Dominanz und Maximalität. Der Punkt p2 wird
genau dann von einem Punkt p1 dominiert, falls sich dieser „rechts oberhalb“ (durch
Schraffierung hervorgehoben) von p2 befindet. In der Abbildung wird p2 also von p1 dominiert. Würde sich kein Punkt in der schraffierten Ebene befinden, so wäre p2 maximal.
In diesem Beispiel ist p1 ein maximaler Punkt, p2 hingegen nicht.
y
p1=(x1,y1)
p2=(x2,y2)
x
Abbildung 1: Dominanz und Maximalität im R2
Gegeben sei nun eine endliche Menge P ⊆ R2 . Wir wollen die Pareto-Menge von P
berechnen. Dieses Problem ist auch bekannt als Maximum Vector Problem.
12
Der folgende Algorithmus ist ein Spezialfall des in [5, 6] vorgestellten Algorithmus, der in Zeit O(n(log n)d−2 ) + O(n log n) die maximalen Punkte einer vorgegebenen endlichen Menge P ⊆ Rd berechnet. Im Falle des R2 ist die worst-case-Laufzeit
O(n log n) optimal. Beim Beweis der Optimalität argumentiert man über untere Schranken für bestimmte Sortierverfahren.
Algorithmus
Maximal-Points(P)
Eingabe: Array P von Punkten mit x-Koordinate P[k][1] und y-Koordinate P[k][2]
Ausgabe: Die Pareto-Menge von P als Array
1 Sortiere P primär nach x-Koordinate und sekundär nach y-Koordinate,
sodass P[1][1] 6 P[2][1] 6 . . . 6 P[length[P]][1] und
P[j][2] 6 P[j + 1][2] 6 P[j + m][2], falls P[i][1] = P[i + 1][1]
für i ∈ { j, j + 1, . . . , j + m − 1 }.
2 return Maximal-Points-Recursive(P)
Maximal-Points-Recursive(P)
1
2
3
4
5
6
7
8
if length[P] = 1
then return P
else Pl ← P[1 . . b n
2 c]
n
Pr ← P[b 2 c + 1 . . length[P]]
Ml ← Maximal-Points-Recursive(Pl )
Mr ← Maximal-Points-Recursive(Pr )
M ← Merge-Maximal-Points(Ml , Mr )
return M
Merge-Maximal-Points(Ml , Mr )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
nl ← length[Ml ]
nr ← length[Mr ]
ymax ← Mr [1][2]
for i ← 2 to nr
do if Mr [i][2] > ymax
then ymax ← Mr [i][2]
M ← newArray(0)
for i ← 1 to nl
do if Ml [i][2] > ymax
then length[M] ← length[M] + 1
M[length[M]] ← Ml [i]
length[M] ← length[M] + nr
M[length[M] − nr + 1 . . length[M]] ← Mr
return M
Der Algorithmus Maximal-Points wird auf einer durch
ein Array kodierten Punktmenge P ⊆ R2 aufgerufen (vgl. Abbildung 2). Diese wird primär nach der x-Koordinate und sekundär nach der y-Koordinate aufsteigend sortiert. Der
Erläuterung und Korrektheit
13
Sortiervorgang in Zeile 1 des Algorithmus Maximal-Points kann z.B. mit einem stabilen
Sortieralgorithmus wie Merge-Sort durchgeführt werden, indem durch zwei hintereinander ausgeführte Aufrufe von Merge-Sort die Elemente des Arrays P zunächst nach
der y-Koordinate und dann nach der x-Koordinate sortiert werden.
Abbildung 2: Eine Punktmenge P ⊆ R2
Nach dem Sortieren wird im Algorithmus Maximal-Points-Recursive rekursiv auf
der Menge P operiert. Die Menge der Punkte P wird zunächst in eine „linke“ Teilmenge
Pl und eine „rechte“ Teilmenge Pr annähernd gleicher Größe geteilt (vgl. Abbildung 3).
Pl
Pr
Abbildung 3: Aufteilung der Punktmenge P in zwei Teilmengen Pl und Pr
Für die beiden Mengen Pl und Pr werden rekursiv jeweils die Mengen Ml und Mr der
maximalen Punkte berechnet. Die maximalen Punkte von Pl bzw. Pr sind in Abbildung 4
durch Linien miteinander verbunden.
Pl
Pr
Abbildung 4: Rekursive Berechnung der maximalen Punktmengen Ml und Mr
Anschließend werden die beiden Paretomengen Ml und Mr mit dem Algorithmus
Merge-Maximal-Points zusammengefügt, und das Ergebnis M wird zurückgegeben.
Dies ist offensichtlich ein Divide-&-Conquer-Ansatz. Der Rekursionsabbruch findet bei
einer Menge, die aus genau einem Punkt besteht, statt. Die Menge der maximalen Punkte
besteht dann trivialerweise genau aus diesem Punkt.
Die meiste Arbeit steckt im Zusammenfügen der beiden maximalen Mengen Ml und
Mr zu einer Menge M, die maximal für P sein soll:
14
Zunächst beobachtet man, dass kein Punkt pr = (xr , yr ) ∈ Pr von einem Punkt pl =
(xl , yl ) ∈ Pl dominiert werden kann: Da das Array P primär nach x-Koordinate und
sekundär nach y-Koordinate (aufsteigend) sortiert ist, gilt xl 6 xr , und im Falle xl = xr
gilt yl 6 yr . Folglich wird pr nicht von pl dominiert.6
Es kann aber sehr wohl Punkte in Pr geben, die Punkte aus Pl dominieren. Dabei genügt
es, die Punkte in Ml zu bestimmen, die von Punkten aus Mr dominiert werden. Es sei
ml = (xl , yl ) ∈ Ml beliebig. Für alle Punkte mr = (xr , yr ) ∈ Mr gilt dann xr > xl . Der
Punkt ml ist also in P genau dann maximal, wenn es keinen Punkt mr = (xr , yr ) ∈ Mr
mit yr > yl gibt. Es genügt daher den Wert einer größten y-Koordinate ymax bzgl. aller
Punkte aus Mr zu berechnen und dann zu bestimmen, welche Punkte aus Ml eine größere
y-Koordinate als ymax besitzen. Genau diese Punkte aus Ml sind maximal in P.
Es gibt auch eine grafische Interpretation: Man zieht eine zur x-Achse parallele Gerade
durch die Punkte in Mr mit der größten y-Koordinate (vgl. Abbildung 5).
Pl
Pr
Abbildung 5: Berechnung von ymax
Alle Punkte in Ml , die sich auf oder unterhalb dieser Geraden befinden, sind nicht
maximal in P. Die Punkte in Ml oberhalb dieser Geraden sind hingegen maximal in P.
Die for-Schleife in Zeile 8 des Algorithmus Merge-Maximal-Points übernimmt gerade
die Punkte aus Ml , die maximal in P sind, in das Array M (vgl. Abbildung 6).
Pl
Pr
Abbildung 6: Elimination von Punkten in Ml , die von Punkten in Mr dominiert werden
Wir hatten zuvor beobachtet, dass kein Punkt aus Pr von einem Punkt aus Pl dominiert
werden kann, d.h. alle Punkte in Pr sind maximal in P. Daher werden diese in Zeile 13
des Algorithmus Merge-Maximal-Points am Ende des Arrays M angefügt. Insgesamt
erhalten wir die Pareto-Menge M von P (vgl. Abbildung 7). Man bemerke außerdem,
dass die Menge M wiederum primär nach x-Koordinate und sekundär nach y-Koordinate
(aufsteigend) sortiert ist.
6 Für
die Argumentation haben wir an dieser Stelle implizit vorausgesetzt, dass die Punkte im Array P
paarweise verschieden sind.
15
Abbildung 7: Die Pareto-Menge M von P
Es bezeichne T (n) die worst-case-Laufzeit des Algorithmus MaximalPoints-Recursive. Dann gilt
Laufzeitanalyse
T (n) = 2T
n
+ cn = O(n log n)
2
Die worst-case-Laufzeit lässt sich noch verbessern, indem zur Verwaltung der maximalen
Punkte ein balancierter binärer Suchbaum verwendet wird. Man erhält dann die Rekurrenzgleichung T (n) = 2T ( n
2 ) + c log n = O(n). Die worst-case-Laufzeit des Algorithmus
Maximal-Points ist aber in beiden Fällen O(n log n) aufgrund des vorab durchgeführten
Sortiervorgangs.
Das Maximum Vector Problem tritt in vielen unterschiedlichen Kontexten auf und ist als solches daher tiefgehend untersucht worden. Es hat neue Bedeutung
durch sogenannte Skyline Queries (erstmals eingeführt in [1]) für relationale Datenbanken gewonnen. Bei Skyline Queries werden die maximalen Tupel über einer Menge von
Tupeln gesucht. Bestimmte Spalten, deren zugrundeliegenden Domänen linear geordnet
sind, werden als Skyline-Kriterien designiert. Dominanz wird dann bzgl. dieser Kriterien
definiert. Die nicht-dominierten, d.h. maximalen Tupel formen dann die Skyline-Menge
und somit das Ergebnis einer Skyline Query.
Beispiel:
Anwendungen
Name
Aga
Fol
Kaz
Neo
Tor
Uma
Sterne
**
*
*
***
***
**
Distanz
0.7
1.2
0.2
0.2
0.5
0.5
Preis
1175
1237
750
2250
2550
980
Tabelle 2: Die Tabelle Hotel [3]
Die folgende Skyline-Abfrage auf einer Tabelle Hotel, die die Spalten Name, Adresse,
Sterne (Qualitätsmaß), Distanz (Distanz zum Strand) und Preis besitzt, fragt nach den
Hotels, für die sich kein Hotel finden lässt, das zugleich mindestens genauso viele Sterne
besitzt, mindestens genauso nah am Strand ist und mindestens genauso günstig ist:
16
SELECT
Name, Adresse
FROM
Hotel
SKYLINE OF Sterne MAX,
Distanz MIN,
Preis
MIN;
Das Resultat der Abfrage ist in der Tabelle 2 fett hervorgehoben. Man kann die Daten aus
Tabelle 2 als Punkte im dreidimensionalen Raum visualisieren. Die Aufgabe besteht dann
darin die maximalen Punkte zu bestimmen. Das entspricht gerade der Ergebnismenge
der obigen Skyline-Abfrage.
Aufgabe 10
Es sei G = (V, E) ein ungerichteter Graph mit V = { v1 , . . . , vn }. Gegeben sei weiterhin die
Adjazenzmatrix A = (aik ) ∈ { 0, 1 }n×n von G, sodass gilt
aik = 1 ⇔ { vi , vk } ∈ E
(r)
Es sei r > 1 beliebig. Setze A(r) := Ar und sei A(r) = (aik ). Wir behaupten, dass dann
(r)
aik die Anzahl der Wege der Länge (genau) r vom Knoten vi zum Knoten vk in G
angibt. Dazu führen wir Induktion nach r. Der Induktionsanfang für r = 1 ist klar. Es
sei nun r > 1 und die Behauptung korrekt für r − 1. Seien i, k ∈ { 1, 2 . . . , n }. Wir wollen
die Anzahl der Wege der Länge r vom Knoten vi zum Knoten vk in G ermitteln. Dazu
überlegt man sich, dass sich ein Weg der Länge r aus einem Weg der Länge r − 1 und
einer anschließenden Kante zusammensetzt. Es genügt also alle Kanten vj , vk ∈ E, die
zum Knoten vk inzident sind, zu betrachten und die Anzahl der Wege von vi nach vj der
Länge r − 1 jeweils aufzusummieren, d.h. die Anzahl der Wege von vi nach vk der Länge
r ist gegeben durch
X
{ vj ,vk }∈E
(r−1)
aij
=
n
X
(r−1)
aij
ajk = (A(r−1) A)ik = (A(r) )ik .
j=1
Damit ist auch der Induktionsschritt gezeigt und die Behauptung folgt mit dem Prinzip
der vollständigen Induktion.
Berücksichtigt man nun, dass Dreiecke in G Kreise der Länge 3, also Wege der Länge 3
mit gleichem Start- und Endknoten sind, so genügt es im Wesentlichen die Spur der Matrix D := A3 , d.h. die Summe der Diagonaleinträge von D zu berechnen. Da es innerhalb
eines Dreiecks genau 6 Kreise der Länge 3 gibt, muss der so berechnete Wert anschließend noch durch 6 dividiert werden, um die Anzahl der Dreiecke in G zu bestimmen.
Der nachfolgende Algorithmus Count-Triangles führt die beschriebene Idee aus.
17
Count-Triangles(A)
1
2
3
4
5
6
7
Eingabe: n × n-Adjazenzmatrix kodiert als zweidimensionales Array A
D ← newArray(rows[A], rows[A])
D ← Strassen-Matrix-Multiplication(A, A)
D ← Strassen-Matrix-Multiplication(D, A)
s←0
for i ← 1 to rows[D]
do s ← s + D[i][i]
return 6s
Die Korrektheit des Algorithmus folgt mit den vorhergehenden Überlegungen. Die
Laufzeit ist Θ(nlog2 7 ) wenn der Algorithmus von Strassen zur Matrixmultiplikation verwendet wird.
Literatur
[1] Börzsönyi, S. ; Kossmann, D. ; Stocker, K.: The Skyline Operator. In: 17th International Conference on Data Engineering (ICDE’ 01). Washington - Brussels - Tokyo : IEEE,
April 2001, S. 421–432
[2] Cormen, Thomas H. ; Leiserson, Charles E. ; Rivest, Ronald L. ; Stein, Clifford: Introduction to Algorithms. Second Edition. MIT Press and McGraw-Hill Book Company,
2001
[3] Godfrey, Parke ; Shipley, Ryan ; Gryz, Jarek: Algorithms and analyses for maximal
vector computation. In: VLDB J 16 (2007), Nr. 1, S. 5–28
[4] Graham, Ronald L. ; Knuth, Donald E. ; Patashnik, Oren: Concrete Mathematics.
Second Edition. Reading, Massachusetts : Addison-Wesley, 1994
[5] Kung, H. T. ; Luccio, Fabrizio ; Preparata, Franco P.: On Finding the Maxima of a
Set of Vectors. In: Journal of the ACM 22 (1975), Nr. 4, S. 469–476
[6] Preparata, F. P. ; Shamos, M. I.: Computational Geometry: an Introduction. Berlin :
Springer, 1985
[7] Wikipedia. Türme von Hanoi.
BCrme_von_Hanoi. 5 2007
URL:http://de.wikipedia.org/wiki/T%C3%
18
Herunterladen