der Universität Oldenburg

Slides:



Advertisements
Ähnliche Präsentationen
Einführung in die Programmiersprache C/C++
Advertisements

Ziele von EINI I + II Einführen in „Informatik“
der Universität Oldenburg
der Universität Oldenburg
der Universität Oldenburg
Objektorientierte Programmierung
der Universität Oldenburg
Imperative Programmierung
der Universität Oldenburg
Imperative Programmierung
der Universität Oldenburg
der Universität Oldenburg
der Universität Oldenburg

der Universität Oldenburg
Imperative Programmierung
Objektorientierte Programmierung Definition von Klassen
der Universität Oldenburg
der Universität Oldenburg
der Universität Oldenburg
Gliederung Motivation / Grundlagen Sortierverfahren
Java: Objektorientierte Programmierung
Java: Dynamische Datentypen
Indirekte Adressierung
FH-Hof Indirekte Adressierung Richard Göbel. FH-Hof Einfache Speicherung von Daten Eine "einfache" Deklaration definiert direkt eine Speicherplatz für.
Java: Referenzen und Zeichenketten
Java: Grundlagen der Objektorientierung
Strukturen. In einer Struktur kann eine beliebige Anzahl von Komponenten (Daten) mit unterschiedlichen Datentypen (im Gegensatz zu Feldern) zusammengefaßt.
Polymorphie (Vielgestaltigkeit)
Polymorphie (Vielgestaltigkeit)
Objekte und Arbeitsspeicher
Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 7 Claudio Moraga, Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
Universität Dortmund, Lehrstuhl Informatik 1 EINI II Einführung in die Informatik für Naturwissenschaftler und Ingenieure.
Imperative Programmierung Funktionen und Parameter
Imperative Programmierung
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer Diskrete Mathematik I Vorlesung Listen-
Thema des Informatikkurses der Klasse 8
Das Java-Hamstermodell
int dezi = Integer.parseInt(args[0]); boolean vz = (dezi>=0);
Arrays,Strings&Pointer in C/C++
DVG Methoden 1 Methoden. 2 int dezi = Integer.parseInt(args[0]); boolean vz = (dezi>=0); dezi = Math.abs(dezi); String Bin = ""; do { } while.
DVG Klassen und Objekte

Grundkonzepte Java - Klassendefinition
Rekursion mit Listen: Quicksort
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Einführung in die Programmiersprache C 3.Tag Institut für Mathematische Optimierung - Technische Universität Braunschweig.
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
Einführung in die Programmierung
Einführung in die Programmierung Wintersemester 2008/09 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fakultät.
Grundlagen der Informatik 4 Lehrstuhl für Betriebssysteme 1 Wie werden Funktionen realisiert? Beispiel: int maximum(int x, int y) { int j = x; if (y >
Informatik 1 Letzte Übung.
Institut für Wirtschaftsinformatik – Software Engineering, JKU Linz 1 Algorithmen und Datenstrukturen SS 2005 Mag.Th. Hilpold u. Dr. A.Stritzinger Institut.
Dynamische Datentypen
2.4 Rekursion Klassifikation und Beispiele
Prof. Dr.-Ing. Franz-Josef Behr
Algorithmen und Datenstrukturen Übungsmodul 8
Institut für Wirtschaftsinformatik – Software Engineering, JKU Linz 1 Algorithmen und Datenstrukturen SS 2005 Mag.Th. Hilpold u. Dr. A.Stritzinger Institut.
Mag. Thomas Hilpold, Universität Linz, Institut für Wirtschaftsinformatik – Software Engineering 1 Algorithmen und Datenstrukturen 1 SS 2002 Mag.Thomas.
Programmierkurs JavaUE 4 Anweisungen und ProgrammeDietrich BolesSeite 1 Programmierkurs Java Dr. Dietrich Boles Teil Imperative Programmierung Unterrichtseinheit.
Mag. Thomas Hilpold, Universität Linz, Institut für Wirtschaftsinformatik – Software Engineering 1 Algorithmen und Datenstrukturen 1 SS 2002 Mag.Thomas.
Funktionen. Aufgabe : Eingabe zweier Zahlen ---> Minimum bestimmen Dann nochmals Eingabe zweier Zahlen ---> Minimum bestimmen.
Funktionen (Zweck und Eigenschaften) Funktionen sind Unterprogramme, die einen bestimmten Zweck erfüllen Sie zerlegen Probleme in kleine, abgeschlossene.
Pointer. * und &  Bei der Definition int var1; ○ // „normale“ Variable int *var2; ○ // Zeiger auf einen Integer int *var2 = NULL; ○ // … incl. Initialisierung.
Rekursion – Speicherverwaltung
Implementieren von Klassen
 Präsentation transkript:

der Universität Oldenburg Programmierkurs Java Vorlesung am FB Informatik der Universität Oldenburg Vorlesung 7 Dietrich Boles

Gliederung von Vorlesung 7 Speicherverwaltung Stack „Zeiger“ Heap Inkarnationen von Funktionen von Variablen Rekursion Definitionen rekursive Prozeduren rekursive Funktionen Endlosrekursion Backtracking Beispielprogramme

Speicherverwaltung Programm- speicher Programmcode Statische Daten globale Variablen Stack lokale Variablen Daten unter Programmkontrolle Heap

Verwaltung durch Laufzeitsystem Stack Verwaltung durch Laufzeitsystem Arbeitet nach dem Prinzip „last-in-first-out“ Verwaltung von Funktionsaktivierungen Speicherbereich für lokale Variablen p(); return; void p(): int a char b void main(): void main(): void main(): int a float b int a float b int a float b Stack Stack Stack

Programmkontrollierte Verwaltung Heap Programmkontrollierte Verwaltung Speicherzuweisung per Anweisung (new/delete) Zugriff über „Zeiger-Variablen“ (Referenz-Variablen) Unterstützung durch Laufzeitsystem (Garbage Collection, ...) int a int a new int (a); delete (b); char b char b Heap Heap

Zeiger Gibt es in Java so nicht, aber Grundlage für Objektrepräsentation Datentyp ADDRESS ADDRESS-Variablen: Speicherung von Speicheradressen Stack oder Heap Stack oder Heap ADDRESS v 2 Heap Heap 1 1 2 double v 3 2 3 234.567 4 5 4 5

Zeiger ADDRESS(double) v, w; // Anlegen zweier ADDRESS- // Variablen auf dem Stack v = new double(); // Speicherplatzzuweisung (Heap) w = new double(); // v und w enthalten als Werte // Speicheradressen *v = 4711.0; // Zuweisung eines Wertes an die // Speicheradresse, auf die v zeigt *w = *v + 34.567; // dito für w (Dereferenzierung) v = w // v und w zeigen nun auf denselben // Speicherplatz delete v; // Speicherplatzfreigabe delete w;

Funktionsinkarnationen beim Aufruf einer Funktion f ensteht eine Inkarnation von f zur Inkarnation einer Funktion gehören: ein Ausführungspunkt Speicherplätze für funktionslokale Variablen eine Inkarnation wird vernichtet, wenn die Funktion verlassen wird Blockanweisungen entsprechen namenlosen Funktionen, entsprechend gilt der Inkarnationsbegriff auch hier Variableninkarnationen wird während der Programmausführung die Definitionsanweisung einer Variablen v erreicht, entsteht eine Inkarnation (Instanz) von v die Inkarnation von v wird vernichtet, sobald die Lebensdauer von v beendet ist

Aktionen beim Aufruf einer Funktion Inkarnation Aktionen beim Aufruf einer Funktion es wird auf dem Stack ein Aktivierungssegment (Speicherstück) angelegt der aktuelle Zustand des Programms (Registerinhalte) wird im Aktivierungssegment gespeichert im Aktivierungssegment werden Speicherbereiche für Parameter, lokale Variable und temporäre Daten reserviert Aktionen beim Verlassen einer Funktion mit Hilfe der abgespeicherten Registerinhalte kann der Zustand des Programms von vor dem Funktionsaufruf wiederhergestellt werden der Funktionswert wird an geeigneter Stelle abgelegt das Aktivierungssegment wird zerstört

Inkarnation Schema: main(): f1(): f2(int j): int i; int i; float x; int j; return; f2(5+j); Stack j x j f2 f2 x i i i i f1 f1 f1 j f1 j main i main i main i main i main i

Rekursion „Definition eines Problems, einer Funktion oder eines Verfahrens durch sich selbst“ bereits bekannt: direkt rekursive Syntaxdiagramme: indirekt rekursive Syntaxdiagramme: Mathematik: <boolescher Ausdruck> :: „true“ | „false“ | „(“ <boolscher Ausdruck> „)“ ; <Anweisung> ::= ... | <while-Anweisung> ; <while-Anweisung> ::= „while“ „(“ <bA> „)“ <Anweisung> ; { n! = 1 falls n = 0 n * (n-1)! sonst

Rekursive Prozeduren und Funktionen Definition (Rekursion): Eine Funktion heißt rekursiv, wenn mindestens zwei Inkarnationen dieser Funktion zur gleichen Zeit bestehen können. Definition (direkte Rekursion): Eine Funktion heißt direkt rekursiv, wenn sich die Funktion selbst aufruft, d.h. wenn die zweite Inkarnation der Funktion durch die Funktion selbst erzeugt wird. Definition (indirekte Rekursion): Eine Funktion heißt indirekt rekursiv, wenn die zweite Inkarnation der Funktion nicht durch die Funktion selbst erzeugt wird. Definition (Rekursionstiefe): Anzahl der Inkarnationen einer Funktion minus 1

Rekursive Prozeduren Der Hamster soll bis zur nächsten Wand laufen! Iterative Lösung: Direkt rekursive Lösung: void zurMauer() { while (vornFrei()) vor(); } void zurMauerR() { if (vornFrei()) { vor(); zurMauerR(); }

Rekursive Prozeduren Der Hamster soll alle Körner auf dem aktuellen Feld einsammeln! Iterative Lösung: Direkt rekursive Lösung: void sammle() { while (kornDa()) nimm(); } void sammleR() { if (kornDa()) { nimm(); sammleR(); }

Rekursive Prozeduren Korrelation zwischen iterativen und rekursiven Prozeduren: void p() { while ( <Bedingung> ) <Anweisung> } void p1() { if ( <Bedingung> ) { <Anweisung> while ( <Bedingung> ) } void p2() { if ( <Bedingung> ) { <Anweisung> while ( <Bedingung> ) } } } void pR() { if ( <Bedingung> ) { <Anweisung> pR(); }

Rekursive Prozeduren Der Hamster soll bis zur nächsten Wand und dann zurück zur Ausgangsposition laufen! Iterative Lösung: void hinUndZurueck() { int anzahl = 0; while (vornFrei()) { vor(); anzahl++; } linksUm(); linksUm(); while (anzahl > 0) { anzahl--;

Rekursive Prozeduren Der Hamster soll bis zur nächsten Wand und dann zurück zur Ausgangsposition laufen! Direkt rekursive Lösung: void hinUndZurueckR() { if (vornFrei()) { vor(); hinUndZurueckR(); } else { kehrt(); } void kehrt() { linksUm();

Rekursive Prozeduren Schema: main: hUZR (1.) hUZR (2.) hUZR (3.) hUZR(); vornFrei -> t vor(); hUZR(); -----> vornFrei -> t hUZR(); -----> vornFrei -> f kehrt(); <----- Befehlsfolge: vor(); vor(); kehrt(); vor(); vor();

Rekursive Prozeduren Der Hamster soll bis zur nächsten Wand und dann zurück zur Ausgangsposition laufen! Indirekt rekursive Lösung: void hinUndZurueckR() { if (vornFrei()) { laufe(); } else { linksUm(); linksUm(); } void laufe() { vor(); hinUndZurueckR();

Rekursive Funktionen Der Hamster soll die Anzahl an Schritten bis zur nächsten Mauer zählen! Iterative Lösung: Rekursive Lösung: int anzahlSchritte() { int anzahl = 0; while (vornFrei()) { vor(); anzahl++; } return anzahl; int anzahlSchritteR() { if (vornFrei()) { vor(); return anzahlSchritteR() + 1; } else return 0; }

Rekursive Funktionen Schema: main: aSR (1.) aSR (2.) aSR (3.) i=aSR(); vornFrei -> t vor(); aSR() -----> vornFrei -> t aSR() -----> vornFrei -> f return 0; <----- return 0 + 1; 1 return 1 + 1; 2 i=2;

Rekursive Funktionen mit lokalen Variablen Der Hamster soll die Anzahl an Körnern im Maul zählen! int anzahlKoernerR() { if (!maulLeer()) { gib(); int anz = anzahlKoernerR(); nimm(); // Vermeidung von Seiteneffekten! return anz + 1; } else return 0; } Stack aKR anz aKR anz aKR anz ... aKR anz aKR anz aKR anz main main main main

Rekursive Funktionen mit Parametern Der Hamster soll „anz“-Schritte nach vorne gehen! void vorR(int anz) { if ((anz > 0) && vornFrei()) { vor(); vorR(anz-1); } Stack vorR anz=0 vorR anz=1 vorR anz=1 ... vorR anz=2 vorR anz=2 vorR anz=2 main main main main

Rekursive Funktionen / Endlosrekursion Rekursionstiefe: im Prinzip „unendlich“! erzeugt im allgemeinen einen Laufzeitfehler: Stack overflow! Dem Java-Interpreter kann man die gewünschte Stackgröße mitteilen! void sammleR() { if (kornDa()) { sammleR(); nimm(); }

Rekursive Prozeduren und Funktionen Anmerkungen: zu jedem rekursiv formulierten Algorithmus gibt es einen äquivalenten iterativen Algorithmus Vorteile rekursiver Algorithmen: kürzere Formulierung leichter verständliche Lösung Einsparung von Variablen teilweise sehr effiziente Problemlösungen (z.B. Quicksort) Nachteile rekursiver Algorithmen: weniger effizientes Laufzeitverhalten (Overhead beim Funktionsaufruf) Verständnisprobleme bei Programmiernanfängern Konstruktion rekursiver Algorithmen „gewöhnungsbedürftig“

Backtracking-Verfahren Prinzip: Versuch, eine Teillösung eines gegebenen Problems systematisch zu einer Gesamtlösung auszubauen falls in einer gewissen Situation ein weiterer Ausbau einer vorliegenden Teillösung nicht mehr möglich ist („Sackgasse“), werden eine oder mehrere der letzten Teilschritte rückgängig gemacht die dann erhaltene reduzierte Teillösung versucht man auf einem anderen Weg wieder auszubauen Wiederholung des Verfahrens, bis Lösung gefunden wird oder man erkennt, daß keine Lösung existiert Grundlage der Programmiersprache PROLOG! Bekannte Probleme: Springerproblem Acht-Damenproblem Labyrinthsuche

Backtracking-Verfahren Aufgabe: Der Hamster steht am Eingang eines zyklenfreien Labyrinths, in dem er ein Korn finden und auf dem schnellsten Weg zurücktransportieren soll!

Backtracking-Verfahren boolean gefunden = false; void main() { sucheGeradeAb(); } void sucheGeradeAb() { if (kornDa()) { gefunden = true; nimm(); } if (!gefunden && linksFrei()) { linksUm(); vor(); sucheGeradeAb(); vor(); linksUm(); } if (!gefunden && rechtsFrei()) { rechtsUm(); vor(); sucheGeradeAb(); vor(); rechtsUm(); if (!gefunden && vornFrei()) { vor(); sucheGeradeAb(); vor(); } else { kehrt(); } }

{ Beispielprogramm 1 Berechnung der Fakultätsfunktion: n! = 1 falls n = 0 n * (n-1)! sonst public static int fakultaet(int n) { if (n <= 0) return 1; else return n * fakultaet(n-1); } fak(3) = 3 * fak(2) 2 * fak(1) 1 * fak(0) 1 1 * 1 2 * 1 3 * 2 6

{ Beispielprogramm 2 Berechnung einer Fibonacci-Zahl: 1 falls n = 1 fib(n) = 1 falls n = 2 fib(n-1) + fib(n-2) sonst public static int fib(int n) { if (n <= 2) return 1; else return fib(n-1) + fib(n-2); }

{ Beispielprogramm 3 McCarthy-Funktion: es gilt übrigens: mc(n) = 91 für 1 <= n <= 101 { n-10 falls n > 100 mc(n) = mc(mc(n+11)) sonst public static int mc(int n) { if (n > 100) return n - 10; else return mc(mc(n+11)); }

{ Beispielprogramm 4 Ackermann-Funktion: wächst sehr stark: ack(4,2) besitzt 19729 Stellen ack(4,4) ist größer als 10 hoch 10 hoch 10 hoch 19000 { m + 1 falls n = 0 ack(n,m) = ack(n-1,1) falls m = 0 ack(n-1,ack(n,m-1)) sonst public static int ack(int n, int m) { if (n == 0) return m+1; else if (m == 0) return ack(n-1, 1); else return ack(n-1, ack(n,m-1)); }

Beispielprogramm 5 Türme von Hanoi: Gegeben: 3 Pfosten mit n Scheiben Ziel: Lege alle n Scheiben von 1 nach 3 Restriktion 1: immer nur eine Scheibe bewegen Restriktion 2: niemals größere auf kleinere Scheibe 1 2 3 public class Hanoi { public static void main(String[] args) { int hoehe = Terminal.readInt(); verlegeTurm(hoehe, 1, 3, 2); } public static void verlegeTurm(int hoehe, int von, int nach, int ueber) { if (hoehe > 0) { verlegeTurm(hoehe-1, von, ueber, nach); Terminal.out.println(von + “-“ + nach); verlegeTurm(hoehe-1, ueber, nach, von); } } }