Rekursive Funktionen

Ähnliche Dokumente
Rekursive Funktionen

II.3.1 Rekursive Algorithmen - 1 -

Komplexität von Algorithmen OOPM, Ralf Lämmel

Vorkurs Informatik WiSe 17/18

Vorkurs Informatik WiSe 16/17

Speicher und Adressraum

Programmierung mit Feldern OOPM, Ralf Lämmel

12. Rekursion Grundlagen der Programmierung 1 (Java)

Programmieren I. Methoden-Special Heusch --- Ratz 6.1, Institut für Angewandte Informatik

Lösungsvorschlag Serie 2 Rekursion

Einführung in die Informatik I

Prof. Dr. Oliver Haase Karl Martin Kern Achim Bitzer. Programmiertechnik Klassenmethoden Teil 2

Schnittstellen, Stack und Queue

Programmiertechnik Methoden, Teil 2

Programmieren I. Methoden-Spezial Heusch --- Ratz 6.1, Institut für Angewandte Informatik

JAVA - Methoden - Rekursion

Komplexität von Algorithmen

C++ - Kontrollstrukturen Teil 2

Algorithmen. Sortieren durch Auswählen, Sortieren durch Mischen und Vergleich der Laufzeit. Abschätzung der Laufzeit eines Algorithmus, O-Notation.

Mathematische Rekursion

Klassenvariablen, Klassenmethoden

Heap vs. Stack vs. statisch. 6 Speicherorganisation. Beispiel Statische Variablen. Statische Variablen

4. Fortgeschrittene Algorithmen 4.1 Rekursion 4.2 Daten und Datenstrukturen 4.3 Bäume

Aufgabenblatt: Arrays

Heap vs. Stack vs. statisch. 6 Speicherorganisation. Beispiel Statische Variablen. Statische Variablen

Tag 5. Repetitorium Informatik (Java) Dozent: Marius Kamp Lehrstuhl für Informatik 2 (Programmiersysteme)

// Objekt-Methoden: public void insert(int x) { next = new List(x,next); } public void delete() { if (next!= null) next = next.next; } public String

Inhalt Kapitel 2: Rekursion

Programmieren 1 C Überblick

Rekursion. Sie wissen wie man Programme rekursiv entwickelt. Sie kennen typische Beispiele von rekursiven Algorithmen

Grundlagen der Programmierung (Vorlesung 15)

CoMa 04. Java II. Paul Boeck. 7. Mai Humboldt Universität zu Berlin Institut für Mathematik. Paul Boeck CoMa 04 7.

Programmierkurs Java

Algorithmen und Datenstrukturen Tafelübung 4. Jens Wetzl 15. November 2011

11. Rekursion, Komplexität von Algorithmen

Rekursion. Annabelle Klarl. Einführung in die Informatik Programmierung und Softwareentwicklung

Methoden. Gerd Bohlender. Einstieg in die Informatik mit Java, Vorlesung vom

Komplexität von Algorithmen

6 Speicherorganisation

Abschnitt: Algorithmendesign und Laufzeitanalyse

JAVA - Rekursion

! 1. Rekursive Algorithmen.! 2. Rekursive (dynamische) Datenstrukturen. II.3.2 Rekursive Datenstrukturen - 1 -

Grundlagen der Programmierung WS 15/16 (Vorlesung von Prof. Bothe)

Grundzüge der Wirtschaftsinformatik WS 2002/03. Wiederholung Java. Programmierzyklus. Heiko Rossnagel Problem

Algorithmen und Datenstrukturen"

Nachklausur Bitte in Druckschrift leserlich ausfüllen!

Algorithmen und Datenstrukturen (Th. Ottmann und P. Widmayer) Folien: Suchverfahren Autor: Stefan Edelkamp / Sven Schuierer

II. Grundlagen der Programmierung. Beispiel: Merge Sort. Beispiel: Merge Sort (Forts. ) Beispiel: Merge Sort (Forts. )

Algorithmen und Datenstrukturen"

C++ Teil 4. Sven Groß. 30. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 16

Übersicht. Berechnung der Potenz für zwei ganze Zahlen Klausuraufgabe SS 2010! Berechnung der Cosinus-Funktion Klausuraufgabe WS 2010/2011!

Die Schnittstelle Comparable

Einführung in die Programmierung WS 2009/10. Übungsblatt 7: Imperative Programmierung, Parameterübergabe

Schwerpunkte. Verkettete Listen. Verkettete Listen: 7. Verkettete Strukturen: Listen. Überblick und Grundprinzip. Vergleich: Arrays verkettete Listen

Datenstrukturen und Algorithmen

Kapitel 9. Komplexität von Algorithmen und Sortieralgorithmen

Datenstrukturen und Algorithmen

Aufgabe 1 (12 Punkte)

Programmiertechnik II

Numerische Algorithmen OOPM, Ralf Lämmel

Algorithmen und Programmierung II

Kapitel 9. Komplexität von Algorithmen und Sortieralgorithmen

Programmieren I. Kapitel 7. Sortieren und Suchen

Kapitel 5: Paradigmen des Algorithmenentwurfs. Gliederung

Übersicht. Einführung Funktionen in Java Rekursion. 4 Funktionen (in Java) Christian Rössl EinfInf 2017: Funktionen 1

12 Abstrakte Klassen, finale Klassen und Interfaces

Einschub: Anweisungen und Bedingungen für PAP und Struktogramme (1)

! 1. Erste Schritte! 2. Einfache Datentypen! 3. Anweisungen und Kontrollstrukturen! 4. Verifikation! 5. Reihungen (Arrays) II.1.4. Verifikation - 1 -

Rekursion. L. Piepmeyer: Funktionale Programmierung - Rekursion

Martin Unold INFORMATIK. Geoinformatik und Vermessung

Vorlesung Programmieren

9 Türme von Hanoi Bewege Stapel von links nach rechts. In jedem Zug darf genau ein Ring bewegt werden. Es darf nie ein größerer auf einen kleine

Einstieg in die Informatik mit Java

Praktikum zu Einführung in die Informatik für LogWiIngs und WiMas Wintersemester 2017/18. Vorbereitende Aufgaben

Rekursion. Selbstbezug, rekursive Funktionen, rekursive Prozeduren, Terminierung, Effizienz, Korrektheit, Rekursion und Induktion

Einstieg in die Informatik mit Java

Ein Algorithmus heißt rekursiv, wenn er sich selbst aufruft. Meist werden nur einzelne Module eines Gesamtalgorithmus rekursiv verwendet.

Wiederholung Wozu Methoden? Methoden Schreiben Methoden Benutzen Rekursion?! Methoden. Javakurs 2012, 3. Vorlesung

11. Rekursion, Komplexität von Algorithmen

Musterlösung Stand: 5. Februar 2009

Stand der Vorlesung Komplexität von Algorithmen (Kapitel 3)

Informatik I: Einführung in die Programmierung

Kapitel 5: Abstrakte Algorithmen und Sprachkonzepte. Elementare Schritte

Vorlesung Programmieren

Tutoraufgabe 1 (Sortieren): Lösung: Datenstrukturen und Algorithmen SS14 Lösung - Übung 4

Abstrakte Algorithmen und Sprachkonzepte

Rekursion. Beispiel Fakultät (iterativ) Rekursive Java-Implementierung. Beispiel Fakultät (rekursiv) n! = n

EINFÜHRUNG IN DIE PROGRAMMIERUNG

Kasparov versus Deep Blue. Till Tantau. Institut für Theoretische Informatik Universität zu Lübeck

public static void main(string[] args) {

Funktionale Programmierung ALP I. Die Natur rekursiver Funktionen SS Prof. Dr. Margarita Esponda. Prof. Dr.

f 1 (n) = log(n) + n 2 n 5 f 2 (n) = n 3 + n 2 f 3 (n) = log(n 2 ) f 4 (n) = n n f 5 (n) = (log(n)) 2

Elementare Konzepte von

JAVA - Methoden

8. Sortieren II. 8.1 Heapsort. Heapsort. [Max-]Heap 6. Heapsort, Quicksort, Mergesort. Binärer Baum mit folgenden Eigenschaften

Grundlagen der Programmierung

( )= c+t(n-1) n>1. Stand der Vorlesung Komplexität von Algorithmen (Kapitel 3)

EINFÜHRUNG IN DIE PROGRAMMIERUNG

Transkript:

Um Rekursion zu verstehen, muss man vor allem Rekursion verstehen. http://www2.norwalk-city.k12.oh.us/wordpress/precalc/files/2009/05/mona-lisa-jmc.jpg Rekursive Funktionen OOPM, Ralf Lämmel

Was ist Rekursion? (C) Ralf Lämmel, OOPM, Universität Koblenz-Landau 2

Eine Illustration von Rekursion

4 Eine (rekursive) mathematische Definition von! (Fakultät) n! = 1, falls n = 0 n * (n-1)!, falls n > 1

5 Rekursive Berechnung von! 5! = 5 * 4! = 4 * 3! = 3 * 2! = 2 * - 1! = 1 * - 0! = 1

Rekursive Definition von! in Java Umsetzung in Java: // Assume n >= 0 public static int factorial(int n) { if (n == 0) return 1; else return n * factorial(n-1); (C) Ralf Lämmel, OOPM, Universität Koblenz-Landau Siehe package algorithm.factorial 6

7 Aufruf (nicht-) rekursiver Funktionen public class Program { public static int divby2(int x) { return x / 2; public static void main(string[] args) { int x = 5; int y = divby2(x); System.out.println(y);

8 Die Realisierung eines Funktionsaufrufs entspricht dem Entfalten der Funktionsdefinition. Dabei werden formale Parameter durch aktuelle Parameter ersetzt. int x = 5; int y = divby2(x); System.out.println(y); int x = 5; int y = x / 2; System.out.println(y); Die Entfaltung ist statisch möglich für nichtrekursive Funktionen. Die Entfaltung ist notwendigerweise dynamisch (zur Laufzeit) nötig für rekursive Funktionen.

9 Rekursive Funktionsdefinitionen Teile der Definition Basisfall Nichtrekursive Berechnung Rekursiver Fall Rekursive(r) Aufruf(e) Verwertung der (des) Aufrufe(s) Nichtrekursive Berechnung Die Auswahl der Teile erfolgt über Bedingung(en). Es kann auch mehre Fälle jeder Art geben.

10 Rekursive Definition von! // Assume n >= 0 public static int factorial(int n) { if (n == 0) return 1; else Abbruchbedingung Basisfall return n * factorial(n-1); Rekursiver Fall

11! mittels ternärem Operator // Assume n >= 0 Angenommene Vorbedingung (oft ausgelassen) public static int factorial(int n) { return (n == 0)? Abbruchbedingung 1 Basisfall : n * factorial(n-1); Rekursiver Fall

12 Die Fibonacci-Folge Anzahl neugeborener Kaninchen nach n Jahren: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,... Rekursive Funktionsdefinition: fib(n) = 0, falls n = 0 1, falls n = 1 fib(n-2) + fib(n-1), n >= 2

Die Fibonacci-Folge public static int fib(int n) { if (n == 0) return 0; else if (n == 1) return 1; 1. Basisfall 2. Basisfall else return fib(n - 2) + fib(n - 1); 2 rekursive Aufrufe (C) Ralf Lämmel, OOPM, Universität Koblenz-Landau Siehe package algorithm.fibonacci 13

14 Die Fibonacci-Folge (mit Verwendung des ternären Operators) public static int fib(int n) { return n == 0? 0 : n == 1? 1 : fib(n - 2) + fib(n - 1);

15 Anmerkung zur Wahl rekursiver Definitionen Folgende Attribute sind relativ: Eleganz In-/effizienz Beispiel - Die Fibonacci-Folge: Exponentielle Explosion von Aufrufen fib(n) benötigt nur 2 direkte Vorgänger. Effizientere Formulierung darum naheliegend Overhead Stichwort Compiler-Optimierungen

16 Umwandlung der ineffizienten, (binär-)rekursiven Fibonacci-Funktion in eine effiziente, entweder (linear-)rekursive oder iterative Darstellung Naive, rekursive Formulierung Exponentielle Explosion von Aufrufen Schlüsseleigenschaft fib(n) benötigt nur 2 direkte Vorgänger. Effiziente, rekursive Formulierung Vorgänger werden als Parameter gereicht. Effiziente, iterative Formulierung Vorgänger werden in Variablen gehalten.

17 Effiziente, rekursive Formulierung public static int fib(int n) { return fib(n,0,1); public static int fib(int n, int n1, int n2) { return n == 0? n1 : fib(n-1, n2, n1 + n2); Wir überladen den Funktionsnamen. (Wir verwenden verschiedene Argumenttypen.)

18 Effiziente, iterative Formulierung public static int fib(int n) { int n1 = 0; int n2 = 1; for (; n!= 0; n--) { int m1 = n1; int m2 = n2; n1 = m2; n2 = m1 + m2; return n1;

19 Türme von Hanoi Annahmen: N Scheiben verschiedener Durchmesser Stapelung mit abnehmendem Durchmesser 3 Plätze: A, B, C Ziel: Bewegen aller Scheiben von A nach C

20 Türme von Hanoi - Illustration Startkonfiguration Move 1 Move 2 Move 3 Move 4 Move 5 Move 6 Endkonfiguration

21 Türme von Hanoi - Ansatz Ziel: Verschiebung von N Scheiben von A nach C Annahme: Verschieben von N-1 Scheiben möglich Schritte: Verschiebe N-1 Scheiben von A nach B Verschiebe letzte (große) Scheibe von A nach C Verschiebe N-1 Scheiben von B nach C

Türme von Hanoi public class Program { public static void move( int n, String from, String temp, String to) { if (n == 0) return; move(n-1, from, to, temp); Move disc 1 from A to C Move disc 2 from A to B Move disc 1 from C to B Move disc 3 from A to C Move disc 1 from B to A Move disc 2 from B to C Move disc 1 from A to C System.out.println( "Move disc " + n + " from " + from + " to " + to); move(n-1, temp, from, to); public static void main(string[] args) { move(3,"a","b","c"); (C) Ralf Lämmel, OOPM, Universität Koblenz-Landau Siehe package algorithm.hanoi 22

23 Formen von Rekursion Primitive Rekursion Allgemeine Rekursion Endrekursion Lineare Rekursion Binäre Rekursion Indirekte Rekursion

24 Primitive Rekursion Funktion über induktive Struktur von nat. Zahlen Schemavariablen: g, h Schema: f(n) = g, falls n=0 h(n,f(n-1)), sonst Termination ist garantiert. Bestimme g und h! public static int factorial(int n) { if (n == 0) return 1; else return n * factorial(n-1);

25 Beispiel: even/odd (Primitiv-rekursive Variante) // Assume n >= 0 public static boolean even(int n) { return (n<=1)? (n==0) :!even(n-1); // Assume n >= 0 public static boolean odd(int n) { return (n<=1)? (n==1) :!odd(n-1); Eine einfache Verallgemeinerung der primitiven Rekursion mit einem Basisfall > 0

26 Allgemeine Rekursion Keine Einschränkungen an Rekursion Beispiel: McCarty 91-er Funktion: f(n) = n-10, falls x > 100 f(f(n+11)), sonst Eigenschaften: f(n) = 91 für alle n <= 101 f(n) = n - 10 für alle n > 101

27 Beispiel: McCarty 91-er Funktion public static int f(int n) { if (n > 100) return n - 10; else return f(f(n+11)); f(n) = 91 für alle n <= 101 f(n) = n - 10 für alle n > 101

28 Endrekursion Schemavariablen: g, p, r Schema: f(x) = g(x), falls p(x) f(r(x)), sonst Der rekursive Aufruf ist die letzte Operation auf jeder Ebene. http://calvinlawson.files.wordpress.com/2009/02/tail-recursion.jpg Bedeutung: iterative Implementation trivial Endrekursive Formulierung oft relativ einfach Beispiele:!, even/odd nach Anpassung

29 Beispiel: even/odd (Primitiv-rekursive Variante) // Assume n >= 0 public static boolean even(int n) { return (n<=1)? (n==0) :!even(n-1); // Assume n >= 0 public static boolean odd(int n) { return (n<=1)? (n==1) :!odd(n-1);

30 Beispiel: even/odd (End-rekursive Variante) // Assume n >= 0 public static boolean even(int n) { return (n<=1)? (n==0) : even(n-2); // Assume n >= 0 public static boolean odd(int n) { return (n<=1)? (n==1) : odd(n-2);

31 Umwandlung von Endrekursion in eine iterative Formulierung Rekursiv: f(x) = g(x), falls p(x) f(r(x)), sonst Iterativ: f(x) = Solange p(x) nicht gilt x = r(x) Gib g(x) zurück.

32 Beispiel: even/odd (End-rekursive Variante) public static boolean even(int n) { return (n<=1)? (n==0) : even(n-2); public static boolean even(int n) { while (!(n<=1)) n -= 2; return n==0;

33 Umwandlung von primitiver nach End- Rekursion am Beispiel der Fakultät (Verwendung eines Akkumulatorargumentes) Primitive Rekursion: n! = 1, falls n = 0 n * (n-1)!, sonst Endrekursion: n! = factorial(1,n) factorial(x,n) = x, falls n = 0 factorial(x*n, n-1), sonst

34 Beispiel: Fakultät (End-rekursive Variante) public static int factorial(int n) { return (n == 0)? 1 : n * factorial(n-1); public static int factorial(int n) { return factorial(1,n); Wir überladen den Funktionsnamen. (Wir verwenden verschiedene Argumenttypen.) public static int factorial(int x, int n) { return (n==0)? x : factorial(n*x,n-1);

35 Lineare Rekursion Verallgemeinerung von: Primitive Rekursion Endrekursion Schemavariablen: g, p, h, r Schema: f(x) = g(x), falls p(x) h(x,f(r(x))), sonst Einfache Verallgemeinerung: f kann mehrmals referenziert werden...... aber nur einmal ausgewertet werden.

36 Binäre Rekursion Verallgemeinerung von linearer Rekursion Zwei, verschiedenartige rekursive Aufrufe. Beide Aufrufe fallen auch dynamisch an. Beispiel: Die Fibonacci-Funktion

37 Indirekte Rekursion Eine Funktion ruft sich nicht (nur) direkt selbst auf. Stattdessen sind mehrere Funktionen beteiligt. Indirekte Rekursion erleichtert Modularisierung. Beispiel: even(n) = true, falls n = 0 odd(n-1), sonst odd(n) = false, falls n = 0 even(n-1), sonst

38 Beispiel: even/odd (Indirekt-rekursive Variante) // Assume n >= 0 public static boolean even(int n) { if (n==0) return true; else return odd(n-1); // Assume n >= 0 public static boolean odd(int n) { if (n==0) return false; else return even(n-1);

39 Beispiel: even/odd (Kompaktere indirekt-rekursive Variante) // Assume n >= 0 public static boolean even(int n) { return (n==0) odd(n-1); // Assume n >= 0 public static boolean odd(int n) { return!(n==0) && even(n-1);

40 MergeSort Teilung der Eingabe Linke Hälfte Rechte Hälfte Rekursives Sortieren Zwischenergbnis Zwischenergbnis Merge Sortiertes Ergebnis

MergeSort - Beispiel 8 2 4 9 7 8 2 4 9 7 2 4 7 8 9 2 8 4 7 9 8 2 4 9 7 8 2 4 7 9 9 7 9 7 commons.wikimedia.org (C) Ralf Lämmel, OOPM, Universität Koblenz-Landau 41 commons.wikimedia.org

42 Mischen 2 8 4 7 9 2 4 7 8 9

MergeSort - Implementation public static void mergesort(int[] a, int[] temp, int min, int max) { // Cease on trivial sorting problem if (!(min<max)) return; // Divide int middle = ( min + max ) / 2 ; // Solve smaller problems recursively mergesort(a,temp,min,middle); mergesort(a,temp,middle+1,max); // Merge via temporary array merge(a,temp,min,middle,max); (C) Ralf Lämmel, OOPM, Universität Koblenz-Landau Siehe package algorithm.sorting 43

Merge - Implementation public static void merge(int[] a, int[] temp, int min, int middle, int max) { int i = min; // loop over left half int j = middle+1; // loop over right half int k = min; // loop over merged result while (k<=max) temp[k++] = (i <= middle && (j > max a[i] < a[j]))? a[i++] // copy from left half : a[j++]; // copy from right half // Commit temporary result for (k=min; k<=max; k++) a[k] = temp[k]; (C) Ralf Lämmel, OOPM, Universität Koblenz-Landau Siehe package algorithm.sorting 44

45

Zusammenfassung Rekursive Definitionen sind oft elegant. Rekursion kann Kosten verursachen. Konvertierung rekursiv nach iterativ Prinzipiell immer möglich Praktisch oft elegant möglich Ausblick Komplexität von Algorithmen Korrektheit von Programmen