Präsentationsfolien (PDF)
Präsentationsfolien (PDF)
Präsentationsfolien (PDF)
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