DAP2 Präsenzübung 3 - TU Dortmund, Informatik 2

Werbung
SoSe 2017
C. Sohler
A. Krivo²ija, A. Rey, H. Sandvoÿ
DAP2 Präsenzübung 3
Besprechung: 10.05.2017 12.05.2017
: (Rekursionsgleichung)
Gegeben sei die Rekursionsgleichung:
Präsenzaufgabe 3.1
wenn n > 1
sonst
a) Bestimmen Sie eine asymptotische obere Schranke für T (n) und beweisen Sie sie mittels
Induktion. Sie dürfen annehmen, dass n von der Form 2 für ein k ∈ N ist.
b) Begründen Sie, warum die Annahme über n keine Beschränkung der Allgemeinheit darstellt.
(
4 · T (n/2) + n3
T (n) =
1
k
Lösung:
a) Aus dem
Master-Theorem (aus der Vorlesung) würden wir haben, dass f (n) = n , γ ·n =
4·
⇔ γ = ist, wovon folgt T (n) ∈ O(f (n) = O(n ). Da wir aber keine Konstante
für diese Behauptung kennen, sollten wir genaueren Ausdrück herleiten.
Behauptung: T (n) ≤ 2 · n − n = O(n ) (wir nehmen an, dass n eine 2er Potenz ist).
3
n 3
2
1
2
3
3
2
3
n
+ n3
T (n) = 4 · T
2
n n3 n n3
= 4 · 4 · T 2 + 3 + n3 = 42 · T 2 +
+ n3
2
2
2
2
n n3 n3 n3
= 43 · T 3 + 2 + 1 + 0
2
2
2
2
k−1
n
X 1
= . . . = 4k · T k + n3
2
2i
i=0
für alle k, so dass n > 2 . Wenn k = log n, gilt weiter:
k
2
log2 n−1
log2 n
T (n) = 4
3
· T (1) + n
X
1 − 2log12 n
1
2
3
=n ·1+n ·
2i
1 − 12
i=0
1
= n2 + 2n3 · 1 −
= 2 · n3 − n2 = O(n3 )
n
1
3
Die bisherige Analyse ist eher ein intuitives, schlaues Erraten der Lösung. Die Behauptung
ist mittels vollständiger Induktion zu beweisen:
Beweis:
(I.A.) Für n = 1 ist T (n) = 1 ≤ 2 · 1 − 1 = 2 − 1 = 1.
(I.V.) Die Behauptung gelte für ein beliebiges, aber festes n = 2 (n ist eine Zweierpotenz).
(I.S.) Betrachte n = 2 · n (die nächste 2er Potenz). Dann gilt
3
2
0
k0
0
0
T (n)
=
(IV)
4·T
2 · n0
2
+ (2 · n0 )3 = 4 · T (n0 ) + 8 · n30
≤
4 · 2 · n30 − n20 + 8 · n30 = 16 · n30 − 4 · n20
=
2 · (2 · n0 )3 − (2 · n0 )2 = 2 · n3 − n2 .
Damit folgt die Behauptung für alle natürliche Zahlen n.
Anmerkung: der induktive Beweis könnte auch für die Aussage T (n) ≤ c · n , für alle
c ≥ 2, durchgeführt werden. Was man aber nicht beweisen kann, ist dass T (n) ≤ c · n
für eine c < 2 ist. Wenn man aus T (n) ∈ O(n ) behaupten würde, dass T (n) ≤ n ist,
könnte man dies nicht beweisen, weil es falsch ist.
b) Potenzenbehauptung: Es bleibt noch zu begründen, warum die Annahmen über n
(2er-Potenzen) keine Beschränkung der Allgemeinheit darstellen. Wir haben für diese
Rekursionsgleichung gezeigt, dass
2
0
0
3
2
3
T (n) ≤ c · n3
für eine Konstante c > 0 für alle Werte von n gilt, die Zweierpotenzen sind. Ein einfacher
Induktionsbeweis (den wir hier nicht führen wollen) zeigt, dass T (n) monoton wachsend
ist. Damit folgt für n mit 2 ≤ n < 2 :
k
k+1
T (n) ≤ T 2k+1
≤ c · 2k+1
3
= c · 23 · 23k
3
≤ 8 · c · n3 ,
= 8 · c · 2k
d.h., es existiert eine Konstante c > c, nämlich c = 8 · c, so dass auch für alle n (zwischen
zwei Potenzen 2 ≤ n < 2 ) T (n) ≤ c · n gilt.
Wenn wir keine Behauptung über 2er-Potenzen machen würden, müssten wir entweder
behaupten, dass die Teilung in der Rekursionsgleichung (T ( )) ganzzählig ist, oder dass
bei Teilung Ab- bzw. Aufrunden (T (b c) bzw. T (d e)) gegeben ist.
0
k
0
0
k+1
n
2
2
n
2
n
2
: (Teile und Herrsche)
Gegeben sei ein Array A[1..n] von positiven ganzen Zahlen. Wir wollen die gröÿte Wertdierenz
A[i] − A[j] für i ≤ j bestimmen. Z.B. im Array {1, 8, 4, 7} ist die gröÿte Wertdierenz 8 − 4 = 4.
2
Präsenzaufgabe 3.2
a) Entwickeln Sie einen Teile-und-Herrsche Algorithmus, der die gröÿte Wertdierenz berechnet und zurückgibt, und beschreiben Sie ihn mit eigenen Worten. Geben Sie eine
Implementierung Ihres Algorithmus in Pseudocode an. Für die volle Punktzahl wird ein
Algorithmus erwartet, dessen Worst-Case-Laufzeit durch O(n) beschränkt ist.
b) Analysieren Sie die Laufzeit Ihres Algorithmus. Stellen Sie hierzu eine Rekursionsgleichung für die Laufzeit Ihres Algorithmus auf und lösen Sie diese. Hier dürfen Sie behaupten, dass n eine Zweierpotenz ist.
c) Zeigen Sie die Korrektheit Ihres Algorithmus.
Lösung:
a) Die gröÿte Wertdierenz muss mindestens 0 sein, da wir für i = j also A[i] − A[i] = 0
haben. Somit gilt, dass wenn wir das Array der Länge 1 haben, können wir einfach als
gröÿte Wertdierenz 0 zurückgeben. Ansonsten können wir das Array in zwei (gleichgröÿen) Teilarrays teilen, und als gröÿte Wertdierenz kann eine der folgenden drei Fälle
vorkommen:
• die gröÿte Wertdierenz A[i] − A[j] ist im linken Teilarray,
• die gröÿte Wertdierenz A[i] − A[j] ist im rechten Teilarray,
• die gröÿte Wertdierenz hat A[i] im linken Teilarray und A[j] im rechten Teilarray.
Deswegen müssten wir für beiden Teilarrays A und A vom Array A die Werte max
(den maximalen Wert im A ), min (den minimalen Wert im A ) und w (die gröÿte
Wertdierenz im A ) berechnen und zurückgeben (und auch für A ). Nun folgt es dass
es gilt:
• max = max{max , max },
• min = min{min , min },
• w = max{w , w , max − min }.
Für das Array A der Länge 1 gilt: (max , min , w ) = (A[1], A[1], 0).
Diese Beschreibung lässt sich einfach in den Pseudocode MaxDif(Array A, int l, int
r) umwandeln, wobei l und r die Indizes der Grenzen des betrachteten Teilarrays sind,
und das erste Aufruf mit MaxDif(A,1,n) erfolgt.
StartMaxDif(array A):
n ← Length(A)
if n > 0 then
(m , m , w) ← MaxDif(A,1,n)
L
L
R
L
L
L
L
A
L
R
L
R
R
L
R
A
1.
2.
3.
4.
1
L
R
A
A
L
2
return w
3
A
A
MaxDif(array A, int StartIndex, int EndIndex):
if EndIndex = StartIndex then
return (A[StartIndex], A[StartIndex], 0)
else
k ← b(EndIndex + StartIndex)/2c
/* Index des mittleren Elements */
(max , min , w ) ← MaxDif(A, StartIndex, k )
(max , min , w ) ← MaxDif(A, k + 1, EndIndex )
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
L
L
L
R
R
R
maxA ← max{maxL , maxR }
minA ← min{minL , minR }
wa ← max{wL , wR , maxR − minL }
return (maxA , minA , wA )
b) Wir können annehmen, dass n eine Zweierpotenz ist, und damit dass alle Teilarrays auch
die Gröÿe gleich einer Zweierpotenz haben. Die Rekursionsabbruchbehandlung (Zeilen 1
und 2) lässt sich in konstanter Zeit absolvieren. Ansonsten ruft man bei jedem Rekursionsaufruf zwei weitere Aufrufe mit halbierter Gröÿe des Arrays, was man höchstens log n
mal tun kann. Die Restanweisungen und Rekursionsabbruchsbehandlung eine konstante Anzahl der Rechenschritte verlangt. Die Laufzeit des Algorithmus ist durch folgende
Rekursionsgleichung gegeben
(
c
für n = 1
T (n) =
+ c für n > 1
2·T
wobei c und c zwei positive Konstanten sind. Die Lösung davon ist (nach MasterTheorem mit γ = 2 > 1) T (n) ∈ O(n), was die erwünschte Laufzeit des Algorithmus
aus der Teilaufgabe a) ist.
c) Behauptung: Algorithmus MaxDif ndet das maximale Element, das minimale Element und die gröÿte Wertdierenz korrekt bei Eingabe des Arrays der Länge n, ∀n ∈ N.
(I.A.) Wenn n = 1 ist, dann gibt es nur ein Element in dem Array, das das maximale und
minimale Element ist, und das die gröÿte Wertdierenz A[1] − A[1] = 0 ergibt. Das
wird korrekt in den Zeilen 1 und 2 berechnet und zurückgegeben. Die Behauptung
ist deswegen im Induktionsanfang korrekt.
(I.V.) Es gelte dass der Algorithmus MaxDif das maximale Element, das minimale
Element und die gröÿte Wertdierenz korrekt ndet, für alle Arrays deren Eingabelängen kleiner als beliebige aber feste n ∈ N, n > 1.
(I.S.) Sei die Länge des Arrays A gleich n , mit n > 1. Die Bedingung in der Zeile 1. ist
falsch. Wir nden das mittleren Element mit Index k ← b(EndIndex+StartIndex)/2c
in der Zeile 4. Jetzt rufen wir unseren Algorithmus MaxDif auf der ersten Hälfte des
Arrays A und der zweiten Hälfte des Arrays A auf (in den Zeilen 5. und 6.). Da die
Gröÿe der Teilarrays A und A kleiner als n ist, werden nach der Induktionsvoraussetzung die Werte von max , min , w , max , min und w korrekt berechnet.
Denn das maximale Element in A ist gröÿeres aus max und max (korrekt in Zeile
7.); das minimale Element in A ist kleineres aus min und min (korrekt in Zeile 8.);
und nach Vorüberlegungen muss die gröÿte Wertdierenz in A eine der w , w und
max − min sein (korrekt berechnet in Zeile 9). Somit werden die korrekte Werte
in der Zeile 10. auch für das Array der Länge n zurückgegeben.
4
2
1
n
2
1
2
2
0
0
0
0
L
R
L
R
L
0
L
L
R
R
R
L
L
R
R
L
L
R
0
R
Somit gilt die Behauptung für alle natürlichen Zahlen n, d.h. die Korrektheit des Algorithmus ist damit bewiesen.
5
Herunterladen