04.11.2013 Aufrufe

Präsentationsfolien (PDF)

Präsentationsfolien (PDF)

Präsentationsfolien (PDF)

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

Algorithmen und Datenstrukturen<br />

8. Rekursion<br />

Dr.-Ing. Norbert Oster<br />

Department Informatik Martensstraße 3 91058 Erlangen


Vorwarnung: Bitte nicht erschrecken…<br />

• Die Folien dieses Vortrags<br />

□ stammen aus der Vorlesung<br />

„Algorithmen und Datenstrukturen“ (i.W. „Kapitel 8“)<br />

□ hören Studenten verschiedener Studiengänge<br />

i.d.R. im ersten (bis dritten) Semester<br />

□ allerdings erst<br />

etwa in der Mitte des ersten Semesters…<br />

□ … bis dahin haben sie schon etliche Programmier-<br />

Grundlagen am Beispiel der Sprache „Java“<br />

kennengelernt<br />

• Zweck heute:<br />

□ „schnuppern“,<br />

wie eine „echte“ Vorlesung meistens abläuft…<br />

□ … auch wenn nicht alles auf Anhieb zu Verstehen ist<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-2


8. Rekursion<br />

8.1 Einführung der Rekursion<br />

8.2 Türme von Hanoi<br />

8.3 Fibonacci-Zahlen<br />

8.4 Skyline-Problem Teile-und-Herrsche<br />

8.5 Rekursionsformen<br />

8.6 Sortieren durch Mischen („merge sort“)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-3


8.1 Einführung der Rekursion<br />

Eine Geschichte<br />

Es war einmal ein Mann mit 2 Kindern, die eine Geschichte<br />

hören wollten. Der Vater fing an:<br />

Es war einmal ein Mann mit 3 Kindern, die eine Geschichte<br />

hören wollten. Der Vater fing an:<br />

Es war einmal ein Mann mit 4 Kindern, die eine Geschichte<br />

hören wollten. Der Vater fing an:<br />

Und wenn sie nicht gestorben sind,<br />

dann leben sie noch heute.<br />

Und wenn sie nicht gestorben sind,<br />

dann leben sie noch heute.<br />

Und wenn sie nicht gestorben sind,<br />

dann leben sie noch heute.<br />

Stopp – Aufhören!<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-4


8.1 Einführung der Rekursion<br />

Eine Geschichte (in Java)<br />

void geschichte(int x) {<br />

print ("Es war einmal ein Mann mit " + x + " Kindern,"<br />

+ " die eine Geschichte hören wollten.");<br />

if (nochLust()) {<br />

Terminierungsbedingung<br />

print("Der Vater fing an:");<br />

geschichte(x+1);<br />

Rekursionsschritt<br />

}<br />

leerer „else“-Fall, ohne geschichte-Aufruf<br />

print ("Und wenn sie nicht gestorben sind,"<br />

+ " dann leben sie noch heute.");<br />

}<br />

„Nachklappern“<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-5


8.1 Einführung der Rekursion<br />

Rekursive Methodendefinition<br />

• Eine Methode (Prozedur, Funktion) f heißt rekursiv (lat. recurrere),<br />

gdw. zur Berechnung von f diese Methode f wieder benutzt wird.<br />

• f(x) {...} heißt rekursive Methodendefinition,<br />

gdw. f in {...} aufgerufen wird.<br />

Rumpf<br />

• Variante:<br />

Im Rumpf von f steht g, im Rumpf von g steht wieder f.<br />

Keine rekursive Methodendefinition, wohl aber rekursiv.<br />

Stichwort: verschränkte Rekursion.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-6


8.1 Einführung der Rekursion<br />

Zentrale Fragen der Rekursion<br />

• Semantik:<br />

□ Zyklische Definitionen sind in der Regel unbefriedigend.<br />

□ Rekursive Funktionen erlangen erst durch ihre spezifische<br />

Behandlung der Argumente eine Bedeutung – trotz ihrer zyklischen<br />

Struktur.<br />

• Terminierung:<br />

□ Kommt die Berechnung zum Ende?<br />

Wiederum ist die spezifische Behandlung der Argumente wichtig.<br />

□ Nicht rekursiver Basis-/Abbruchfall ist erforderlich.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-7


8.1 Einführung der Rekursion<br />

Fakultätsfunktion (für n>0)<br />

1 falls n=1<br />

n! :=<br />

n · (n-1)! sonst<br />

Rekursive Definition<br />

1! = 1 = 1<br />

2! = 2*1 = 2<br />

3! = 3*2*1 = 6<br />

4! = 4*3*2*1 = 24<br />

5! = 5*4*3*2*1 = 120<br />

6! = 6*5*4*3*2*1 = 720<br />

…<br />

• Java-Code:<br />

long fakultaet(int n) {<br />

if (n == 1) {<br />

return 1;<br />

} else {<br />

Terminierungsbedingung<br />

Basisfall<br />

return n * fakultaet(n - 1);<br />

}<br />

}<br />

„Nachklappern“ Rekursionsschritt<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-8


8.1 Einführung der Rekursion<br />

Java-Code der Fakultätsfunktion<br />

long fakultaet(int n) {<br />

if (n == 1) {<br />

return 1;<br />

} else {<br />

return n * fakultaet(n - 1);<br />

}<br />

}<br />

Ausführung fakultaet(4):<br />

4 .<br />

fakultaet(3)<br />

4 . 6=24<br />

3 .<br />

fakultaet(2)<br />

3 . 2=6<br />

2 . 2 . 1=2<br />

fakultaet(1)<br />

1<br />

„Nachklappern“ mit Hilfe der<br />

offenen Methodenschachteln<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-9


8.1 Einführung der Rekursion<br />

Korrekt gemäß Spezifikation?<br />

• Gegeben:<br />

Spezifikation einer Funktion f (im mathematischen Sinne).<br />

Gefragt:<br />

Berechnet eine in einer Programmiersprache<br />

ausgedrückte Funktion f immer f ?<br />

• Naiver Ansatz („ausprobieren“):<br />

Für jede Eingabe kann das Ergebnis durch schrittweises<br />

Ausführen von f ermittelt werden. Dabei werden Methodenaufrufe<br />

im Methodenschachtelmodell ausgewertet.<br />

• Formaler Ansatz („beweisen“):<br />

Durch Verallgemeinerung Aussage für alle Eingaben ableiten!<br />

Korrektheitsbeweis<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-10


8.1 Einführung der Rekursion<br />

Rekursion als konstruktive Form der Induktion<br />

Rekursionsprinzip<br />

Auswertung f(e) für ein e<br />

Induktion (vollständig)<br />

Beweis P für alle e<br />

• Für einige f(e 0 ) ist der Wert von f<br />

ohne weitere Rekursion feststellbar.<br />

• Versuche einen/mehrere Werte e‘


8.1 Einführung der Rekursion<br />

Korrekt gemäß Spezifikation?<br />

n<br />

• Fakultätsfunktion mathematisch: n! = i=1 i<br />

• Java-Code:<br />

long fakultaet(int n) {<br />

if (n == 1) {<br />

return 1;<br />

} else {<br />

return n * fakultaet(n - 1);<br />

}<br />

}<br />

• Nachweis von fakultaet(n) = n! für alle n<br />

1<br />

□ Induktionsanfang: fakultaet(1) = 1 = i=1 i = 1!<br />

□ Induktionsschluss "nn+1":<br />

fakultaet(n+1) = (n+1)*fakultaet(n) //Ausführung<br />

= (n+1) . n! //Induktionsannahme<br />

n<br />

= (n+1) . i=1 i //Definition von n!<br />

n+1<br />

= i=1 i //Definition von <br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-12


8.1 Einführung der Rekursion<br />

Terminierungsüberlegungen<br />

• Terminierung kann für eine einzelne Eingabe nur im Erfolgsfall<br />

nachgewiesen werden.<br />

• Rekursive Berechnung terminiert, wenn<br />

□ es eine Fallunterscheidung im Rumpf der Funktion gibt,<br />

bei der mindestens ein Fall keinen rekursiven Aufruf enthält<br />

und<br />

□ wenn jeder rekursive Aufruf nach endlich vielen Schritten<br />

einen nicht-rekursiven Fall erreicht.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-13


8.1 Einführung der Rekursion<br />

Skizze für Terminierungsbeweise<br />

• e 0 , e 1 , e 2 , ... sei Argumentfolge der Rekursionsschritte bei<br />

Auswertung von f.<br />

• Finde (ganzzahlige) Terminierungsfunktion t(e i )<br />

und beweise (per Induktion?):<br />

□ t fällt bei jedem Rekursionsschritt streng monoton<br />

□ t ist nach unten beschränkt (z.B. wird nie kleiner als 0).<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-14


8.1 Einführung der Rekursion<br />

Terminierungsbeweis für fakultaet<br />

long fakultaet(int n) {<br />

if (n == 1) {<br />

return 1;<br />

} else {<br />

return n * fakultaet(n - 1);<br />

}<br />

}<br />

• Argumentfolge betrachten: x, x-1, x-2, ...<br />

Terminierungsfunktion finden: t(x) = x<br />

• Nachweis (für ganzzahlige x>0):<br />

□ t(x) ist auf der Folge der Argumente streng monoton fallend bei jedem<br />

Rekursionsschritt (Induktionsbeweis).<br />

□ Bei der impliziten Annahme x ganzzahlig und x>0<br />

ist t(x) nach unten durch 1 beschränkt.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-15


8.1 Einführung der Rekursion<br />

• Der Induktionsgedanke ist ein oft verwendetes Mittel<br />

zum Entwurf von Algorithmen:<br />

□ Bestimme die Lösung für einen Basisfall.<br />

□ Zerlege das Problem in ein, zwei oder mehrere einfache(re)<br />

Teilprobleme, die entweder direkt oder rekursiv lösbar sind<br />

und verknüpfe die Lösung zur Gesamtlösung.<br />

• Beipiel: n! = n . (n-1)!<br />

Teilproblem 1:<br />

trivial<br />

Teilproblem 2:<br />

Rekursiv lösbar<br />

<br />

<br />

Verknüpfung<br />

Der Fall n wird auf den Fall n-1 zurückgeführt.<br />

Die Induktionsannahme wird einmal angewendet.<br />

Rekursion am Ende des Rumpfs.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-16


8.2 Türme von Hanoi<br />

Problemspezifikation<br />

• Gegeben: k Scheiben unterschiedlichen Durchmessers, der Größe<br />

nach geordnet auf Position A. Positionen B und C ohne Scheiben.<br />

A B C<br />

• Problem: Versetze Scheiben-Turm von A nach B, wobei<br />

□ jede Scheibe nur einzeln bewegt werden kann,<br />

□ immer nur die oberste Scheibe eines Turmes bewegt werden kann,<br />

□ niemals eine größere Scheibe auf einer kleineren liegen darf und<br />

□ C zur Zwischenablage benutzt werden kann.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-17


8.2 Türme von Hanoi<br />

Beispiel<br />

• Gegeben: 3 Scheiben unterschiedlichen Durchmessers, der Größe<br />

nach geordnet auf Position A. Positionen B und C ohne Scheiben.<br />

A B C<br />

• Problem: Versetze Scheiben-Turm von A nach B, wobei<br />

□ jede Scheibe nur einzeln bewegt werden kann,<br />

□ immer nur die oberste Scheibe eines Turmes bewegt werden kann,<br />

□ niemals eine größere Scheibe auf einer kleineren liegen darf und<br />

□ C zur Zwischenablage benutzt werden kann.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-18


8.2 Türme von Hanoi<br />

Lösungsansatz: Induktionsprinzip<br />

• Basisfall k=0: keine Scheiben.<br />

Trivial, weil sofort fertig.<br />

• Rückführung auf kleinere Probleme (k>0)<br />

□ Teilproblem 1: Versetze die oberen k-1 Scheiben von A nach C<br />

kleines Problem: rekursiv lösbar<br />

□ Teilproblem 2: Versetze die verbleibende<br />

k-te Scheibe von A auf Turm B<br />

Triviale Elementaroperation<br />

□ Teilproblem 3: Versetze die k-1 Scheiben von C nach B<br />

kleines Problem: rekursiv lösbar<br />

□ Verknüpfung:<br />

Hintereinanderausführung der 3 Teillösungen<br />

Induktionsannahme:<br />

Das Problem ist für die<br />

Versetzung von k-1<br />

Scheiben lösbar.<br />

Gleiche Induktionsannahme<br />

nochmals<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-19


8.2 Türme von Hanoi<br />

• Lösungsansatz: Induktionsprinzip<br />

A B C<br />

k-1 Scheiben<br />

von A nach C<br />

1 Scheibe<br />

von A nach B<br />

k-1 Scheiben<br />

von C nach B<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-20


8.2 Türme von Hanoi<br />

Java-Code<br />

void hanoi(int k, char start, char ziel, char hilfe) {<br />

if (k > 0) {<br />

hanoi(k - 1, start, hilfe, ziel);<br />

System.out.print("Versetze Scheibe " + k);<br />

System.out.print(" von " + start);<br />

System.out.println(" nach " + ziel);<br />

hanoi(k - 1, hilfe, ziel, start);<br />

}<br />

// else-Fall = Basisfall der Induktion ist leer<br />

}<br />

<br />

<br />

Der Fall k wird auf den Fall k-1 zurückgeführt.<br />

Die Induktionsannahme wird doppelt angewendet.<br />

Rekursion nicht nur am Ende des Rumpfs.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-21


8.2 Türme von Hanoi<br />

hanoi(3, ‘A‘, ‘B‘, ‘C‘);<br />

> java Hanoi<br />

Versetze Scheibe 1 von A nach B<br />

Versetze Scheibe 2 von A nach C<br />

Versetze Scheibe 1 von B nach C // zwei Scheiben A C<br />

Versetze Scheibe 3 von A nach B // größte Scheibe am Ziel<br />

Versetze Scheibe 1 von C nach A<br />

Versetze Scheibe 2 von C nach B // zweitgrößte Scheibe am Ziel<br />

Versetze Scheibe 1 von A nach B // fertig<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-22


8.2 Türme von Hanoi<br />

• Korrektheit:<br />

Beweis per Induktion<br />

(kann direkt aus Rekursion abgelesen werden.)<br />

• Terminierung:<br />

Terminierungsfunktion T(x) = x<br />

(Anzahl zu versetzender Scheiben)<br />

□ Streng monoton fallend (per Induktionsbeweis)<br />

□ Nach unten durch 0 beschränkt<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-23


8.3 Fibonacci-Zahlen<br />

• Ursprüngliche Fragestellung<br />

aus dem Jahr 1202<br />

□ Gegeben sei ein neugeborenes<br />

Kaninchenpaar.<br />

Jedes Kaninchenweibchen bringt<br />

jeden Monat ein neues Paar zur Welt.<br />

Junge Kaninchen haben nach 2<br />

Monaten ihre ersten Jungen.<br />

Kaninchen sterben nicht.<br />

□ Gesucht: Wie viele Kaninchenpaare<br />

gibt es nach 12 Monaten?<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-24


8.3 Fibonacci-Zahlen<br />

• Ergebnis:<br />

□ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …<br />

• Rekursive Definition:<br />

□ fibo(0) = 1<br />

□ fibo(1) = 1<br />

□ fibo(n) = fibo(n-2) + fibo(n-1)<br />

• Die so genannten Fibonacci-Zahlen<br />

spielen in der Informatik an ganz<br />

unterschiedlichen Stellen eine Rolle.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-25


8.3 Fibonacci-Zahlen<br />

Lösungsansatz: Induktionsprinzip<br />

• Basisfall:<br />

□ n=0: fibo(0) = 1<br />

□ n=1: fibo(1) = 1<br />

• Rückführung auf kleinere Probleme<br />

□ Teilproblem 1: fibo(n - 2)<br />

□ Teilproblem 2: fibo(n - 1)<br />

□ Verknüpfung: Addition<br />

<br />

<br />

Der Fall n wird auf zwei kleinere Fälle zurückgeführt.<br />

Man benötigt 2 Basisfälle.<br />

Rekursion nicht nur am Ende des Rumpfs.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-26


8.3 Fibonacci-Zahlen<br />

• Fibonacci-Zahlen in Java<br />

<br />

<br />

long fibo(int n) {<br />

if (n


8.3 Fibonacci-Zahlen<br />

Nachteile der rekursiven Lösung<br />

fibo(4)<br />

fibo(2)<br />

Wenn man hier das<br />

Zwischenergebnis von<br />

fibo(2) noch hätte,<br />

könnte man die neue<br />

Berechnung einsparen.<br />

fibo(3)<br />

fibo(0) fibo(1) fibo(1) fibo(2)<br />

fibo(0)<br />

fibo(1)<br />

Diese Darstellung wird Aufrufbaum genannt.<br />

werden jeweils erneut ausgewertet!<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-28


8.3 Fibonacci-Zahlen<br />

Durchreichen von Zwischenergebnissen<br />

long fiboFast(int fim1, int fi, int i, int n) {<br />

//Zwischenergebnis Fibonacci(i - 1) in fim1<br />

// und Fibonacci(i) in fi<br />

if (i >= n) {<br />

return fi;<br />

} else {<br />

return fiboFast(fi, fim1 + fi, i + 1, n);<br />

}<br />

}<br />

long fiboSchnell(int n) {<br />

return fiboFast(1, 1, 1, n);<br />

}<br />

Statt Neuberechung<br />

wird (früheres) Teilergebnis<br />

verwendet.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-29


8.3 Fibonacci-Zahlen<br />

Rekursion bei durchgereichten Zwischenergebnissen<br />

fiboFast (1, 1, 1, 4)<br />

fiboFast (1, 2, 2, 4)<br />

fiboFast (2, 3, 3, 4)<br />

Zwischenergebnisse „rücken auf“<br />

und werden zur Berechnung neuer<br />

Zwischenergebnisse verwendet.<br />

fiboFast (3, 5, 4, 4)<br />

<br />

<br />

Korrektheit und Terminierung wieder per Induktion<br />

leicht zu beweisen.<br />

Durchreichen von Zwischenergebnissen ist eine<br />

grundlegende Programmiermethode.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-30


8.3 Fibonacci-Zahlen<br />

Analyse der Rekursion<br />

long fiboFast(int fim1, int fi, int i, int n) {<br />

//Zwischenergebnis Fibonacci(i - 1) in fim1<br />

// und Fibonacci(i) in fi<br />

if (i >= n) {<br />

return fi;<br />

} else {<br />

return fiboFast(fi, fim1 + fi, i + 1, n);<br />

}<br />

}<br />

Dann wird das Ergebnis von<br />

Methodenschachtel zu<br />

Methodenschachtel kopiert.<br />

5<br />

5<br />

fiboFast (1, 1, 1, 4)<br />

fiboFast (1, 2, 2, 4)<br />

Erst Abstieg bis auf tiefste<br />

Rekursionsebene (Basisfall).<br />

5<br />

5<br />

fiboFast (2, 3, 3, 4)<br />

fiboFast (3, 5, 4, 4)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-31


8.4 Skyline-Problem Teile-und-Herrsche<br />

Problem:<br />

• Gegeben: Exakte Lage und Form von diversen rechteckigen<br />

Gebäuden einer Stadt<br />

• Gesucht: Zeichne die zweidimensionale „Skyline“,<br />

wobei verborgene Linien eliminiert werden<br />

• Gebäude B i wird durch Tripel (L i , H i , R i ) repräsentiert.<br />

□ Dabei stellen L i und R i die Koordinaten der linken bzw. rechten<br />

Ecke des Gebäudes dar. H i ist dessen Höhe.<br />

□ Beispiel: (1,11,5)<br />

11<br />

1 5<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-32


8.4 Skyline-Problem Teile-und-Herrsche<br />

Skyline-Problem am Beispiel<br />

• Gegeben:<br />

1 5 10 15 20 25 30<br />

(1,11,5)<br />

(2,6,7)<br />

(3,13,9)<br />

(12,7,16)<br />

(14,3,25)<br />

(19,18,22)<br />

(23,13,29)<br />

(24,4,28)<br />

• Lösung:<br />

1 5 10 15 20 25 30<br />

Skyline-Beschreibung: (1,11,3,13,9,0,12,7,16,3,19,18,22,3,23,13,29,0)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-33


8.4 Skyline-Problem Teile-und-Herrsche<br />

Lösungsansatz: Induktionsprinzip<br />

• Basisfall: ein Gebäude ist seine eigene Skyline, also trivial.<br />

• Rückführung auf kleinere Probleme:<br />

□ Teilproblem 1: Skyline für n-1 Gebäude berechnen.<br />

□ Teilproblem 2: ein Gebäude: trivial<br />

□ Verknüpfung: „übereinanderlegen“ und neue Skyline koordinatenweise<br />

ablesen.<br />

• Bsp: n-tes Haus: (5,9,26)<br />

Im Unterschied zu früheren<br />

Beispielen ist Verknüpfung<br />

hier recht aufwändig.<br />

1 5 10 15 20 25 30<br />

Skyline (n-1): (1,11,3,13,9,0,12,7,16,3,19,18,22,3,23,13,29,0)<br />

Skyline (n): (1,11,3,13,9,9, 19,18,22,9,23,13,29,0)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-34


8.4 Skyline-Problem Teile-und-Herrsche<br />

• Man kann dafür Korrektheit und Terminierung beweisen.<br />

Allerdings:<br />

• Um das Gebäude n hinzuzufügen, muss der Durchlauf durch die<br />

Skyline der n-1 Gebäude etwa n Stellen überprüfen bzw. ändern:<br />

□ Hinzufügen Gebäude n: n<br />

□ Hinzufügen Gebäude n-1: n-1<br />

□ Hinzufügen Gebäude n-2: n-2<br />

□ …<br />

„Komplexitätstheorie“: O(n²)<br />

□ Hinzufügen Gebäude 1: + 1<br />

□ Gesamt:<br />

½ n(n+1) Überprüfungen/Änderungen<br />

• Bei 16 Gebäuden: 16·17/2 = 136 Schritte<br />

aber es gibt im Allg. mehrere Algorithmen für ein Problem …<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-35


8.4 Skyline-Problem Teile-und-Herrsche<br />

2. Lösungsansatz, ebenfalls Induktionsprinzip<br />

• Basisfall: ein Gebäude ist seine eigene Skyline, also trivial.<br />

• Rückführung auf kleinere Probleme:<br />

□ Teilproblem 1: Skyline für n/2 Gebäude (ggf. aufrunden) berechnen.<br />

□ Teilproblem 2: Skyline für restl. n/2 Gebäude (ggf. abrunden) berechnen.<br />

□ Verknüpfung:<br />

• Beispiel:<br />

• Führe die beiden Skylines zusammen.<br />

• Man spricht von Verschmelzung.<br />

Man kann dafür Korrektheit<br />

und Terminierung beweisen<br />

Verknüpfung nicht langsamer<br />

als im 1-Gebäude-Fall!<br />

Schrittweises Durchlaufen<br />

beider Skyline-Folgen halber<br />

Länge, maximal n Änderungen.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-36


8.4 Skyline-Problem Teile-und-Herrsche<br />

• Allgemein: Die Rekurrenz T(n) = 2 . T(n/2) + n, T(1) = 1<br />

hat für 2er Potenzen n die Lösung<br />

T(n) = n + n . log 2 (n) // Beispiel: T(16) = 16 + 16*4 = 80<br />

• Beweis durch Induktion:<br />

□ Induktionsanfang: T(1) = 1 // trivial<br />

□ Induktionshypothese: Es gilt: T(n/2) = n/2 + n/2 . log 2 (n/2)<br />

□ Induktionsschritt:<br />

T(n) = 2 . T(n/2) + n // nach Definition von T(n)<br />

= 2 . (n/2 + n/2 . log 2 (n/2)) + n // Induktionshypothese<br />

= n + n . log 2 (n/2) + n<br />

= n + n . (log 2 (n/2) + 1)<br />

Wie man leicht erkennt, gilt…<br />

= n + n . log 2 (n) // nach Definition log 2<br />

„Komplexitätstheorie“: O(n · log n) – statt O(n²)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-37


8.4 Skyline-Problem Teile-und-Herrsche<br />

Von Problemgröße abhängiger Aufwand<br />

250<br />

200<br />

Je ein Gebäude einzeln hinzufügen<br />

(20 Gebäude: 210 Schritte)<br />

Schrittzahl<br />

150<br />

100<br />

50<br />

n(n+1)/2<br />

n+n*log(n,2)<br />

Bis n=6 ist der<br />

1. Lösungsansatz<br />

besser, dann<br />

Umstiegspunkt.<br />

0<br />

Problem „halbieren“ und „Verschmelzen“<br />

(20 Gebäude: ca. 106 Schritte)<br />

1<br />

3<br />

5<br />

7<br />

9<br />

11<br />

13<br />

15<br />

17<br />

19<br />

Problemgröße<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-38


8.4 Skyline-Problem Teile-und-Herrsche<br />

Teile-und-Herrsche:<br />

(divide-and-conquer)<br />

= Anwendung des Induktionsprinzips zur Algorithmenkonstruktion<br />

• Prinzip:<br />

□ Zerlegung des Problems in mehrere (deutlich) kleinere Probleme:<br />

• Lösung dieser durch Rekursion (falls groß genug).<br />

• Direkte Lösung oder Basisfall, wenn Problem klein genug ist.<br />

Hier/meistens: 2 Probleme halber Größe.<br />

□ Füge Teillösungen zur Gesamtlösung zusammen, wobei die<br />

Verschmelzung „relativ wenig Aufwand verursacht“.<br />

• Aufwand:<br />

□ Rekurrenz; kann per Induktion nachgewiesen werden.<br />

□ Da es für ein Problem im Allgemeinen mehrere Algorithmen gibt,<br />

bleibt stets die Frage nach dem Aufwand und damit dem besten<br />

Algorithmus für das jeweilige Problem!<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-39


8.5 Hinführung: Blasensortierung („bubble sort“)<br />

Gegeben<br />

• Reihe mit n (zunächst unsortierten) Elementen<br />

10 3 2 5 8 1 4 7<br />

Grundidee<br />

• Die Reihe wird immer wieder durchlaufen und dabei werden<br />

benachbarte Elemente in die richtige Reihenfolge gebracht.<br />

• Größere Elemente überholen so die kleineren und drängen an das<br />

Ende der Folge (= aufsteigende Blasen).<br />

Aufwandsabschätzung<br />

• Im ersten Durchlauf werden n Elementpaare verglichen.<br />

• Im zweiten Durchlauf werden n-1 Elementpaare verglichen.<br />

• …<br />

• Gesamtaufwand: O(n²)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-40


8.5 Hinführung: Blasensortierung („bubble sort“)<br />

Beispiel<br />

10 3 2 5 8 1 4 7<br />

3 10 2 5 8 1 4 7<br />

3 2 10 5 8 1 4 7<br />

…<br />

10 „blubbert hoch“<br />

3 2 5 8 1 4 7 10<br />

2 3 5 8 1 4 7 10<br />

bis hier sortiert<br />

…<br />

8 „blubbert hoch“<br />

2 3 5 1 4 7 8 10<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-41


8.5 Sortieren durch Mischen („merge sort“)<br />

Sortieren durch Mischen („merge sort“)<br />

Grundidee: Teile-und-Herrsche<br />

• Wir können eine Liste der Länge n=2 m , m>0, mit geringem<br />

Aufwand (n/2) in zwei gleich große Teillisten der Länge n/2=2 m-1<br />

zerlegen und mit gleichem Aufwand die Ergebnisse<br />

zusammenfügen (Reißverschluss).<br />

• Leere oder einelementige Mengen sind sortiert.<br />

• Damit gibt es nur noch m = log 2 n Rekursionen.<br />

Aufwandsschätzung (n sei die Länge der Liste)<br />

• Also Gesamtaufwand im schlechtesten Fall: O(n·log 2 n)<br />

eines der schnellsten Sortierverfahren!<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-42


8.5 Sortieren durch Mischen („merge sort“)<br />

Grundprinzip<br />

Rekursion:<br />

1 n<br />

n Basisfälle<br />

Lösung 1. Teil<br />

Lösung 2. Teil<br />

Rekursion<br />

Gesamtlösung<br />

Mischen:<br />

10<br />

7<br />

3<br />

5<br />

4<br />

2<br />

10<br />

7<br />

3<br />

5<br />

4<br />

10<br />

7<br />

5<br />

4<br />

≤<br />

≤<br />

≤<br />

…<br />

2<br />

3<br />

2<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-43


8.5 Sortieren durch Mischen („merge sort“)<br />

Beispiel<br />

10 3 2 5 8 1 4 7<br />

10 3 2 5 8 1 4 7<br />

10 3 2 5 8 1 4 7<br />

10 3 2 5 8 1 4 7<br />

3 10 2 5 1 8 4 7<br />

3 10 2 5 1 8 4 7<br />

2 3 5 10 1 4 7 8<br />

takeAndDrop<br />

1 2 3 4 5 7 8 10<br />

merge<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-44


8.5 Sortieren durch Mischen („merge sort“)<br />

Wichtige Eigenschaften<br />

• mergesort() ist stabil<br />

(gleich Elemente werden nie vertauscht)<br />

• Schnellstes Verfahren auf verketteten Listen<br />

wegen der geringsten Zahl an Vergleichen<br />

• Sequentieller Zugriff auf Teillisten externes Sortierverfahren.<br />

Daher verbreitetes Sortierverfahren für große Listen, die nicht<br />

mehr in den Hauptspeicher passen:<br />

□ Unterteile Datei in Abschnitte.<br />

□ Sortiere jeden der Abschnitte für sich im Hauptspeicher.<br />

□ Speichere sortierten Abschnitt in Hilfsdatei.<br />

□ Verschmelze die Hilfsdateien mit Reißverschlussverfahren. Wichtig<br />

ist dabei, dass die Hilfsdateien sequentiell von links nach rechts<br />

verarbeitet werden. (Das geht schnell und ohne wahlfreien Zugriff.)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-45


8.6 Rekursionsformen<br />

• Lineare Rekursion = eine rekursive Methodendeklaration f<br />

heißt linear rekursiv, wenn in jedem Zweig einer Fallunterscheidung<br />

höchstens einmal f aufgerufen wird.<br />

• Repetitive Rekursion (Rumpf-Rekursion, „tail recursion“) =<br />

Spezialfall der linearen Rekursion, bei dem der rekursive Aufruf<br />

stets als letzte Aktion des Zweigs auftaucht.<br />

□ Repetitive Rekursionen können daher unmittelbar entrekursiviert und<br />

durch Schleifen ersetzt werden<br />

• Kaskadenartige Rekursion = In einem Zweig einer<br />

Fallunterscheidung im Rumpf einer rekursiven Methodendeklaration<br />

f treten zwei oder mehr Aufrufe von f auf.<br />

□ Baumartige Aufrufstruktur<br />

□ Lawinenartiges Anwachsen der anfallenden rekursiven Aufrufe<br />

□ Kaskadenartige Rekursion lässt sich nicht (leicht) in Iterationen<br />

umwandeln.<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-46


8.6 Rekursionsformen<br />

• Verschachtelte Rekursion = die rekursiven Aufrufe<br />

treten nicht nur im Rumpf der Methodendeklaration sondern<br />

zusätzlich bei den aktuellen Parameterausdrücken auf.<br />

int ackermann(int m, int n) {<br />

if (m == 0) return n + 1;<br />

else if (n == 0) return ackermann(m - 1, 1);<br />

else return ackermann(m - 1, ackermann(m, n - 1));<br />

}<br />

• Diese Funktion werden Sie in der theoretischen Informatik<br />

noch intensiv studieren (Stichwort: Berechenbarkeit).<br />

• Sie ist nicht mit primitiver Rekursion (f(n + 1)=h(n, f(n)) ausdrückbar.<br />

• Sie terminiert immer.<br />

• Ihre Werte wachsen jedoch bei Vergrößerung der Argumente<br />

außerordentlich schnell: ackermann(3,3) = 61,<br />

ackermann(2,4) ≈ 10 21000 , ackermann(4,4) ≈ 10 101021000<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-47


8.6 Rekursionsformen<br />

• Verschränkte Rekursion: Methoden rufen sich zyklisch<br />

gegenseitig auf. (Einfacher Fall: Methodendeklaration f enthält einen<br />

Aufruf der Methode g, die wiederum einen Aufruf von f enthält.)<br />

• Beispiel: ist eine Zahl n gerade (oder ungerade)?<br />

boolean isEven(int n) {<br />

if (n == 0) {<br />

return true;<br />

} else if (n == 1) {<br />

return false;<br />

} else {<br />

return isOdd(n-1);<br />

}<br />

}<br />

boolean isOdd(int n) {<br />

if (n == 0) {<br />

return false;<br />

} else if (n == 1) {<br />

return true;<br />

} else {<br />

return isEven(n-1);<br />

}<br />

}<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-48


8.6 Rekursionsformen<br />

• Verschränkte Rekursion: Methoden rufen sich zyklisch<br />

gegenseitig auf. (Einfacher Fall: Methodendeklaration f enthält einen<br />

Aufruf der Methode g, die wiederum einen Aufruf von f enthält.)<br />

• Beispiel: binäre Quersumme von n<br />

Hat die Binärdarstellung von n eine ungerade Zahl von Einsen?<br />

boolean qsumIs1(int n) {<br />

if (n == 0) return false; // Quersumme ist nicht 1<br />

else if ((n % 2) == 0)<br />

return qsumIs1(n / 2); // wenn gerade, dann muss binäre<br />

// Quersumme der Hälfte 1 sein.<br />

else return qsumIs0(n / 2); // wenn ungerade, dann muss bin.<br />

// Quersumme der Hälfte 0 sein.<br />

// Achtung / ist Div ohne Rest.<br />

}<br />

boolean qsumIs0(int n) {<br />

// analog<br />

}<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-49


8.6 Rekursionsformen<br />

• Beispiel: binäre Quersumme<br />

boolean qsumIs1(int n) {<br />

if (n == 0) return false;<br />

else if ((n % 2) == 0)<br />

return qsumIs1(n / 2);<br />

else return qsumIs0(n / 2);<br />

}<br />

boolean qsumIs0(int n) {<br />

if (n == 0) return true;<br />

else if ((n % 2) == 0)<br />

return qsumIs0(n / 2);<br />

else return qsumIs1(n / 2);<br />

}<br />

qsumIs1(42) 0101010<br />

qsumIs1(21) 010101<br />

qsumIs0(10) 01010<br />

qsumIs0(5) 0101<br />

qsumIs1(2) 010<br />

qsumIs1(1) 01<br />

qsumIs0(0) 0<br />

true<br />

Hat die Binärdarstellung von 42 eine ungerade Zahl von Einsen?<br />

42 = 32+8+2=101010 binär<br />

qsumIs1(42)<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-50


8.6 Rekursionsformen<br />

• Fakultätsfunktion: lineare Rekursion<br />

(Durchreichen-Variante: repetitiv)<br />

• Türme von Hanoi: kaskadenartige Rekursion<br />

• Fibonacci-Zahlen: kaskadenartige Rekursion;<br />

Durchreichen von Zwischenergebnissen<br />

liefert repetitive Rekursion;<br />

umgebaut in Iteration.<br />

• Skyline-Problem: kaskadenartige Rekursion<br />

• Sortieren durch Mischen: kaskadenartige Rekursion<br />

• Gerade/Ungerade: verschränkte Rekursion<br />

• Binäre Quersumme: verschränkte Rekursion<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-51


Vielen Dank für‘s Zuhören<br />

• Fragen?<br />

Algorithmen und Datenstrukturen Philippsen/Stamminger/Pflaum/Riehle WS 2010/2011 Folie 08-52

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!