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