2.4 Rekursion versus Iteration

Ähnliche Dokumente
2 Programmiermethodik 2.1 1

II.3.1 Rekursive Algorithmen - 1 -

3.2.6 Sprünge. Hier: Beschränkung auf gute Sprünge wie return break continue. Beachte: Ein Sprung hat keinen Effekt auf die Programmvariablen.

C++ - Kontrollstrukturen Teil 2

Speicher und Adressraum

Klassenvariablen, Klassenmethoden

Software Entwicklung 1. Rekursion. Beispiel: Fibonacci-Folge I. Motivation. Annette Bieniusa / Arnd Poetzsch-Heffter

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

Objektorientierte Programmierung (ZQ1u2B)

PK-Einstufungstest. 1. Allgemeine Multiple-Choice-Aufgaben

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

Rekursive Funktionen

PK-Einstufungstest. 1. Allgemeine Multiple-Choice-Aufgaben. Aufgabe 1.1. Alle Aufgaben beziehen sich auf Java.

Mathematische Rekursion

8 Anwendung: Suchen. Folge a ganzer Zahlen; Element x. Wo kommt x in a vor?

EINI WiMa. Einführung in die Informatik für Naturwissenschaftler und Ingenieure. Vorlesung 2 SWS WS 11/12

FHZ. K13 Rekursion. Lernziele. Hochschule Technik+Architektur Luzern Abteilung Informatik, Fach Programmieren. Inhalt

Institut für Programmierung und Reaktive Systeme 2. Februar Programmieren I. Übungsklausur

Rekursive Funktionen

Inhalt Kapitel 2: Rekursion

Algorithmen und Datenstrukturen 04

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

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

Algorithmen und Datenstrukturen 04

OOP Aufgabenblatt 7 6. Dezember 2013

Einführung in die Informatik I

Software Entwicklung 1

public class Test extends MiniJava { public static void main (String [] args) { write(args[0]+args[1]); } } // end of class Test

Technische Universität München WiSe 2018/19 Fakultät für Informatik Übungsblatt 6 Dr. Ch. Herzog 26. November 2018

Algorithmen und Datenstrukturen II

Elementare Konzepte von

Girls Day 2017 Programmierung

Lösungsvorschlag Serie 2 Rekursion

Grundlagen der Programmierung (Vorlesung 15)

UE Algorithmen und Datenstrukturen 1 UE Praktische Informatik 1. Übung 3

9. Rekursion. 1 falls n 1 n (n 1)!, andernfalls. Experiment: Die Türme von Hanoi. Links Mitte Rechts. Mathematische Rekursion

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

Einstieg in die Informatik mit Java

Musterlösung Stand: 5. Februar 2009

Institut für Programmierung und Reaktive Systeme 25. Januar Programmieren I. Übungsklausur

Stack. Seniorenseminar Michael Pohlig

Informatik I Für eine feste Zahl. Informatik I Benutzereingaben Eine Funktion factorial Iteration von unten. 18.

7. Einführung in C++ Programmieren / Algorithmen und Datenstrukturen 1 Prof. Dr. Bernhard Humm FB Informatik, Hochschule Darmstadt

C++ Teil 5. Sven Groß. 12. Nov IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Nov / 16

Kapitel 5: Abstrakte Algorithmen und Sprachkonzepte. Elementare Schritte

Beispiele: Funktionsabstraktion (3) Funktionsdeklaration. Funktionsdeklaration (2) Funktionsdeklaration (3) 3. Abstraktion über Funktionsbezeichner:

Probeklausur Programmieren in C Sommersemester 2007 Dipl. Biol. Franz Schenk 12. April 2007, Uhr Bearbeitungszeit: 105 Minuten

PK-Einstufungstest. 1. Allgemeine Multiple-Choice-Aufgaben. Alle Aufgaben beziehen sich auf Java.

Der Datentyp String. Stringvariable und -vergleiche

Städtisches Gymnasium Olpe Java Ht Informatik - Q1 Die Klasse List im Abitur Methoden und Beispielcode Hier alle wichtigen Methoden. Ein Beispielcode

String s1, s2; Eine Zuweisung geschieht am einfachsten direkt durch Angabe des Strings eingeschlossen in doppelte Hochkommata:

Einführung in die Programmierung Wintersemester 2010/11

1.4 Unterprogramme Strukturierung

Programmierung für Mathematik (HS13)

Software Entwicklung & Programmierung - 0. Übungsblatt

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

Einführung in die Funktionale Programmierung mit Haskell

JAVA 04: Funktionen, Parameter und globale und lokale Variablen.

C.3 Funktionen und Prozeduren

Einführung in die Programmierung für NF. Arrays

Funktionale Programmierung ALP I. Funktionen höherer Ordnung. Teil 2 SS Prof. Dr. Margarita Esponda. Prof. Dr.

C++ Teil 5. Sven Groß. 16. Nov Sven Groß (IGPM, RWTH Aachen) C++ Teil Nov / 16

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

TECHNISCHE UNIVERSITÄT MÜNCHEN FAKULTÄT FÜR INFORMATIK

Funktionale Programmierung ALP I. Funktionen höherer Ordnung SS Prof. Dr. Margarita Esponda. Prof. Dr. Margarita Esponda

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

Einführung in die Programmierung Wintersemester 2017/18

UE Algorithmen und Datenstrukturen 1 UE Praktische Informatik 1. Übung 7. Entrekursivierung

Erste Java-Programme (Scopes und Rekursion)

Java. public D find(k k) { Listnode K, D n = findnode(k); if(n == null) return null; return n.data; Java

11. Rekursion. 1, falls n 1. n (n 1)!, andernfalls. Mathematische Rekursion. Rekursion in Java: Genauso! Unendliche Rekursion. n!

Beispiele für Ausdrücke. Der imperative Kern. Der imperative Kern. Imperativer Kern - Kontrollstrukturen. Deklarationen mit Initialisierung

Fakultät IV Elektrotechnik/Informatik

Universität München, Hans-Peter Kriegel und Thomas Seidl Informatik II a[0] a[1] a[2] a[3] a[n 1]

Zweite Möglichkeit: Ausgabe direkt auf dem Bildschirm durchführen:

Informatik II. Woche 15, Giuseppe Accaputo

Einführung in das Programmieren Probeklausur Lösungen

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

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

12. Rekursion. 1, falls n 1. n (n 1)!, andernfalls. Lernziele. Mathematische Rekursion. Rekursion in Java: Genauso! n! =

6. Unterprogramme. 6.1 Strukturierung von Programmen 6.2 Vereinbarung von Unterprogramme 6.3 Aufruf von Unterprogrammen 6.4 Parameterübergabe

Hochschule Augsburg, Fakultät für Informatik Name:... Prüfung "Programmieren 1", IN1bac, WS 10/11 Seite 1 von 6

Programmieren I. Kapitel 5. Kontrollfluss

Vorkurs Informatik WiSe 17/18

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

Einführung Datentypen Verzweigung Schleifen. Java Crashkurs. Kim-Manuel Klein May 4, 2015

Kapitel 7: Rekursion. Inhalt. Rekursion: Technik Rekursion vs. Iteration

Javakurs 12: Methoden

Technische Informatik I Übung 3: Assembler

Rekursion. Rekursive Funktionen, Korrektheit, Terminierung, Rekursion vs. Iteration, Sortieren

2.5 Backtracking. 1 Ausgang. Beispiel: ungerichteter Graph: Ausweg aus einem Labyrinth suchen, modelliert als. Sackgasse. Ecken. Kanten 2.

Einführung in die Programmierung für Wirtschaftsinformatik

Kapitel 08: Rekursion und Terminierung Software Entwicklung 1

Programmiertechnik Übungen zu Klassen & -methoden

Informatik II Prüfungsvorbereitungskurs

JAVA - Methoden - Rekursion

Rekursion. Rekursive Funktionen, Korrektheit, Terminierung, Rekursion vs. Iteration, Sortieren

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

Transkript:

2.4 Rekursion versus Iteration Beispiel Fakultätsfunktion (factorial): Spezifikation (= applikatives Programm): fact n = if n<2 then 1 else n*fact(n-1) imperativ: int fact(int n){ return n<2? 1 : n*fact(n-1); und iterativ: int fact(int n){ int result = 1; while(n>1) result *= n--; return result; 2.4 1

iterativ: rekursiv: schneller - denn Unterprogrammaufrufe kosten Zeit; schöner, einfacher, naheliegender, besser? int pos(int x) { // position of x in a[] for(int i=0; ; i++) if(x==a[i]) return i; int pos(int x, int i) { //... at i or beyond return x==a[i]? i : pos(x,i+1); Was ist besser? 2.4 2

int position(int unten, int oben) { // Einschachteln, // rekursiv, aus 2.3.1 int zeiger = (unten+oben)/2; if (a[zeiger]< x) return position(zeiger,oben); else if(a[zeiger]==x) return zeiger; else /* a[zeiger]> x */ return position(unten,zeiger); int position(int unten, int oben) { // iterativ, aus 2.1.3 for(;;){ int zeiger = (unten+oben)/2; if (a[zeiger]< x) unten = zeiger; else if(a[zeiger]==x) return zeiger; else /* a[zeiger]> x */ oben = zeiger;? Systematische Umwandlung Iteration Rekursion? 2.4 3

Ein anderes Beispiel stimmt skeptisch: reverse[] = [] reverse(x:xs) = reverse xs ++ [x] String reverse(string s) { // poor efficiency! return s.length()==0? "" : reverse(s.substring(1)) + s.charat(0); String reverse(string s) { // good efficiency! char[] a = s.tochararray(); for(int i=0; i<a.length/2 ; i++) { char x = a[i]; a[i] = a[a.length-1-i]; a[a.length-1-i] = x; return new String(a); 2.4 4

Beispiel für einfache Umwandlungsregel: der Effekt von while(c){ S kann auch erzielt werden durch Aufruf von void whilecs() { if(c){s; whilecs(); Beachte: Beim rekursiven Abstieg wird S wiederholt, beim rekursiven Aufstieg passiert nichts mehr! void whilecs(){ while(c){ S void whilecs() { if(c){s; whilecs(); 2.4 5

... und verallgemeinert: void loop() { // iterative for(;;) { S1 if(c1) return; S2 if(c2) return;... void loop() { // recursive S1 if(c1) return; S2 if(c2) return;... loop(); 2.4 6

Entrekursivierung ist eine Programmtransformation, die eine rekursive Prozedur in eine iterative Prozedur umwandelt, ist von Bedeutung, weil: iterativ braucht weniger Zeit und Speicher, Spezifikation ist häufig rekursiv formuliert. Systematische Verfahren? 2.4 7

2.4.1 Entrekursivierung endrekursiver Prozeduren Zur Erinnerung: Ein Prozeduraufruf erzeugt eine Inkarnation (activation, instance) der Prozedur, die beim Rücksprung beendet wird (und verloren geht). Ein rekursiver Aufruf heißt schlicht, wenn unmittelbar nach Beendigung der erzeugten Inkarnation auch die erzeugende Inkarnation beendet wird. 2.4 8

Verschiedene Rekursionsarten, je nach dem möglichen (dynamischen) Verhalten einer Inkarnation: nichtlineare Rekursion: dynamisch mehr als ein rekursiver Aufruf, z.b. fibonacci hanoi(1.4.3) qsort(2.3.2) lineare Rekursion: dynamisch höchstens ein rekursiver Aufruf, z.b. loop position pos gcd(1.4.3) fact reverse Endrekursion: alle rekursiven Aufrufe sind schlicht, z.b. loop position pos gcd(1.4.3) Endrekursion ist am einfachsten, auch für die Entrekursivierung: 2.4 9

2.4.1.1... ohne Parameter T proc() {locals... return E; // recursive... return proc();... return E;... return proc();... T proc() {locals loop: for(;;) {... return E; // iterative... continue loop;... return E;... continue loop;... Beachte: nichtlokale Variable unproblematisch lokale Variable unproblematisch (bei Entrekursivierung - nicht in umgekehrter Richtung!) Bei T=void muss implizites return explizit gemacht werden! 2.4 10

2.4.1.2... mit Parametern T proc(a a) {locals... return G(a); // recursive... return proc(f(a));... T proc(a a) {locals loop: for(;;) {... return G(a); // iterative... a = F(a); continue loop;... (lokale und nichtlokale Variable auch hier unproblematisch) 2.4 11

Beispiel 1: Euklidischer Algorithmus (1.3.4, 1.4.3 ): static int gcd(int a, int b) { if(b==0) return a; else return gcd(b,a%b); static int gcd(int a, int b) { loop: for(;;) { if(b==0) return a; else {// (a,b) = (b,a%b); int r = a%b; a = b; b = r; continue loop; Vergleiche dies mit 1.3.4, S. 29! 2.4 12

Beispiel 2: Einschachtelungsverfahren: int position(int unten, int oben) { int zeiger = (unten+oben)/2; if (a[zeiger]< x) return position(zeiger,oben); else if(a[zeiger]==x) return zeiger; else /* a[zeiger]> x */ return position(unten,zeiger); int position(int unten, int oben) { loop: for(;;) { int zeiger = (unten+oben)/2; if (a[zeiger]< x) unten = zeiger; // oben = oben; else if(a[zeiger]==x) return zeiger; else /* a[zeiger]> x */ oben = zeiger; // unten=unten; (continue loop; bereits gestrichen, vgl. S. 3) 2.4 13

Beispiel 3: mit Objektaufrufen class Spelling { // linked list of Strings String word; Spelling next; Spelling(String w, Spelling n) { word = w; next = n; void insert(string w) { if(next==null next.word.compareto(w)>0) next = new Spelling(w,next); else if(next.word.equals(w)); /* ignore */ else next.insert(w); boolean check(string w) { if(word.equals(w)) return true; else if(next==null) return false; else return next.check(w); 2.4 14

Modifizierte Technik: Zielobjekt des Operationsaufrufs als zusätzlichen Parameter betrachten boolean check(string w) { // check(x,w) Spelling x = this; // simulate parameter x if(x.word.equals(w)) return true; else if(x.next==null) return false; else return x.next.check(w); // check(x.next,w) boolean checkiter(string w) { // iterative version Spelling x = this; loop: for(;;) if(x.word.equals(w)) return true; else if(x.next==null) return false; else x = x.next; // w = w; // continue loop; 2.4 15

2.4.2 Nicht endrekursive Prozeduren Einbettung (embedding) erlaubt Entrekursivierung bei linearer Rekursion: finde zu der gegebenen Prozedur p0 eine verallgemeinerte Version p1, die endrekursiv ist und die Leistung der gegebenen Prozedur umfasst; ersetze den Rumpf von p0 durch einem Rumpf, der aus einem Aufruf von p1 besteht und bestätige dadurch die Verwendbarkeit von p1; ersetze den Rumpf von p1 durch eine iterative Version und erhalte dadurch eine gleichnamige Version p2; ersetze in p0 den Aufruf von p1 durch den Rumpf von p2. 2.4 16

Beispiel 1: static int fact(int n) { if(n<2) return 1; else return n*fact(n-1); static int fact(int n, int acc) { // using accumulator if(n<2) return acc; else return f(n-1,n*acc); static int fact(int n) { return fact(n,1); 2.4 17

static int fact(int n, int acc) { // using accumulator for(;;) if(n<2) return acc; else acc *= n--;// (n,acc)=(n-1,n*acc) Vereinfachung: while(n>1) acc *= n--; return acc; static int fact(int n) { int acc = 1; // einbettender Parameter wird lokale Variable while(n>1) acc *= n--; return acc; Endversion - vgl. S. 1! 2.4 18

String reverse(string s) { Beispiel 2 (vgl. S. 4) return s.length()==0? "" : reverse(s.substring(1)) + s.charat(0); Einbettung: String reverse(string s, String acc) { if(s.length()==0) return acc; else return reverse(s.substring(1),s.charat(0)+acc);... benutzt in neuer Version: String reverse1(string s) { return reverse(s,""); Einbettung iterativ: String reverseiter(string s, String acc) { for(;;) if(s.length()==0) return acc; else{acc = s.charat(0)+acc; s = s.substring(1); Neue Version mit vereinfachter iterativer Einbettung: String reverseiter(string s) { String acc = ""; while(s.length()!=0) { acc = s.charat(0)+acc; s = s.substring(1); return acc;... bringt aber kaum Effizienzgewinn.

Nichtlineare Rekursion ( hanoi, qsort,...): Umwandlung in Iteration erfordert weitergehende Hilfsmittel ( ALP III) 2.4 20

2.4.3 Umwandlung von Schleifen in rekursive Funktionen Gegeben: eine Schleife Gesucht: eine Haskell-Funktion Feststellung: Dies ist prinzipiell einfacher als Entrekursivierung, weil Rekursion ausdrucksstärker als Iteration ist. Zur Erinnerung (S. 5): der Effekt von while(c){ S kann auch erzielt werden durch Aufruf von void whilecs() { if(c){s; whilecs(); Zu lösen bleibt: imperativer Zustand funktionale Argumente 2.4 21

Allgemeine Form der while-schleife (S. 5) über dem Zustand z eines Programms: void whilecf() { while( C(z) ) z = F(z); void whilecf() { if( C(z) ) { z = F(z); whilecf(); Argumente statt nichtlokaler Variablen: T whilecf(t z) { if(c(z)) return whilecf(f(z)); else return z; D.h. Effekt der Schleife wird durch z = whilecf(z) erzielt. 2.4 22

Direkte Umformulierung nach Haskell liefert whilecf z C z = whilecf(f z) otherwise = z Resümee: void whilecf() { while( C(z) ) z = F(z); whilecf z C z = whilecf(f z) otherwise = z 2.4 23

C und F zu Argumenten machen! Allgemein verwendbares Funktional als Entwurfsmuster (2.3 ): while :: (t->bool) -> (t->t) -> t -> t while cond func init cond init = while cond func (func init) otherwise = init 2.4 24

Beispiel: Approximation der Quadratwurzel x = a mit Newton-Verfahren: x i+1 = (x i + a/x i ) / 2 (z.b. mit x 0 = 1) while(math.abs(x*x-a) > eps) x = (x+a/x)/2; Zustand: z = (a,x,eps), dabei a und eps konstant. Bedingung: inaccurate a x eps = abs(x*x-a) > eps Änderung: improve a x eps = (a, (x+a/x)/2, eps)... und damit sqrt = while inaccurate improve... und damit z.b. sqrt 2 1 0.0001 (2, 1.414..., 0.0001) 2.4 25