2. 5 Verzweigte Rekursion und Backtracking-Verfahren 2. 5

Slides:



Advertisements
Ähnliche Präsentationen
8. Termin Teil B: Wiederholung Begriffe Baum
Advertisements

Hash-Tabellen und -Funktionen Hash-Tabellen in Java
Eine dynamische Menge, die diese Operationen unterstützt,
Vorlesung Programmieren II
Claudio Moraga; Gisbert Dittrich
Das LCA – Problem in Suffixbäumen
Zusammenfassung der Vorwoche
7. Natürliche Binärbäume
Kapitel 6. Suchverfahren
R. Der - Vorlesung Algorithmen und Datenstrukturen (Magister)
der Universität Oldenburg
Java: Objektorientierte Programmierung
Sortierverfahren Richard Göbel.
Java: Dynamische Datentypen
Sortierverfahren Richard Göbel.
SWITCH - Anweisung.
Objekte werden als Adressen (Referenzen) übergeben. Dies führt manchmal zu unerwarteten Ergebnissen...
Polymorphie (Vielgestaltigkeit)
Objekte und Arbeitsspeicher
FOR Anweisung. Aufgabe : Ausgabe aller ganzen Zahlen von 0 bis 100 auf dem Bildschirm.
Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen.
DO...WHILE Anweisung.
Algorithmentheorie 04 –Hashing
Suche in Texten: Suffix-Bäume
WS Algorithmentheorie 05 - Treaps Prof. Dr. Th. Ottmann.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (02 – Funktionenklassen) Prof. Dr. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (13 – Offenes Hashing) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (19 - Analyse natürlicher Bäume) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (02 – Funktionenklassen) Tobias Lauer.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (02 – Funktionenklassen) Prof. Dr. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (27 – Kürzeste Wege) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Bäume: Grundlagen und natürliche Suchbäume) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (18 - Bäume: Durchlaufreihenfolgen, Analyse nat. Bäume) Prof. Th. Ottmann.
WS Prof. Dr. Th. Ottmann Algorithmentheorie 09 - Suche in Texten Suffix - Bäume.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (05 – Elementare Datenstrukturen) Prof. Th. Ottmann.
Vorlesung Informatik 3 Einführung in die Theoretische Informatik (17 –Turingmaschinen) Prof. Dr. Th. Ottmann.
Universität Dortmund, Lehrstuhl Informatik 1 EINI II Einführung in die Informatik für Naturwissenschaftler und Ingenieure.
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
Klausur „Diskrete Mathematik II“
PKJ 2005/1 Stefan Dissmann Methoden (Motivation) Idee: Identische Programmabschnitte zusammenfassen und mit einem Namen versehen Vorteile: Übersichtlichkeit.
PRJ 2007/1 Stefan Dissmann Motivation Problem: gleiche Datenstrukturen werden für verschiedene Objekte gebraucht: z.B. Listen von Studierenden, Kunden,
PKJ 2005/1 Stefan Dissmann Ausblick Es fehlen noch: Möglichkeiten zum Strukturieren größerer Programme Umgang mit variabler Zahl von Elementen Umgang mit.
PKJ 2005/1 Stefan Dissmann Rückblick auf 2005 Was zuletzt in 2005 vorgestellt wurde: Klassen mit Attributen, Methoden und Konstruktoren Referenzen auf.
PKJ 2005/1 Stefan Dissmann Zusammenfassung Vorwoche Programm besteht aus mehreren Bestandteilen: Schlüsselwörter Sonderzeichen Bezeichner Kommentare Texte.
PKJ 2005/1 Stefan Dissmann Zusammenfassung der Vorwoche Variable stehen für (einen) Wert, der sich im Programmablauf ändern kann. Variablen besitzen einen.
Zusammenfassung Vorwoche
PKJ 2005/1 Stefan Dissmann Zusammenfassung Vorwoche Methoden sind mit einem Namen versehene Programmabschnitte besitzen Rückgabetyp, Namen, Parameterliste.
Christian Schindelhauer
Programmierung 1 - Repetitorium WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage:
Verzweigung.
PRJ 2007/1 Stefan Dissmann Verkettete datenstruktur: Liste Problem: Liste, die eine beliebige Zahl von Elementen verwaltet Operationen: Erzeugen, Anfügen,
7.1 Externes Suchen Bisherige Algorithmen: geeignet, wenn alle Daten im Hauptspeicher. Große Datenmengen: oft auf externen Speichermedien, z.B. Festplatte.
Einführung in die Programmierung
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
Effiziente Algorithmen
Polynome und schnelle Fourier-Transformation
Einführung in die Programmierung Wintersemester 2009/10 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Einführung in die Programmiersprache C 4
2.4 Rekursion Klassifikation und Beispiele
Vorlesung Binärer Suchbaum II-
Variablenkonzept Klassisch, in Java Basistyp
Unterprogramme in JAVA
Algorithmen und Datenstrukturen Übungsmodul 8
Christian Schindelhauer Wintersemester 2006/07 2. Vorlesung
CuP - Java Achte Vorlesung Entspricht ungefähr Kapitel 4.1 des Skriptums Montag, 28. Oktober 2002.
Java Syntaxdiagramme Buchstabe A B Z a z ... Ziffer
Binärbäume.
Programmiersprachen II Fortsetzung Datenstrukturen Hashing Prof. Dr. Reiner Güttler Fachbereich GIS HTW.
 Präsentation transkript:

2. 5 Verzweigte Rekursion und Backtracking-Verfahren 2. 5 2.5    Verzweigte Rekursion und Backtracking-Verfahren 2.5.1    Türme von Hanoi

Türme von Hanoi: Logisches Puzzle Gegeben: 3 Pflöcke (start, ziel, hilf), verschieden große Scheiben, der Größe nach geordnet, alle auf Pflock start. Ziel: alle Scheiben auf Pflock ziel bewegen, dort wieder der Größe nach geordnet. Bedingung: Auch zwischendurch darf niemals eine größere Scheibe auf einer kleineren liegen!

Lösungsstrategie: rekursiv! Sei n die Höhe des jeweils zu versetzenden Turmes. move(n,start,ziel,hilf) Falls n=1, einzige Scheibe von start nach ziel sonst 1. move(n-1,start,hilf,ziel); 2. letzte Scheibe von start nach ziel; 3. move(n-1,hilf,ziel,start).

Implementation in Java import java.io.*; public class hanoi { public static void move(String start, String goal) { System.out.println("Move from "+start+" to "+goal); } public static void moves(int n, String start, String goal, String aux) { if (n==1) move(start,goal); else { moves(n-1,start,aux,goal); move(start,goal); moves(n-1,aux,goal,start); } } public static void main(String args[]) { moves(3,"a","c","b");

2.5.2    Erzeugung fraktaler Muster durch verzweigt rekursive Turtle-Programme Beispiel: Koch-Kurve (Schneeflockenkurve)

Turtle: virtueller Zeichenroboter Zustand: Position Blickrichtung Grundbefehle: moveTurtle (Vorwärts- bzw. Rückwärtsschritt) turnTurtle (Drehung auf der Stelle) Turtle kann eine Spur hinterlassen und so Figuren zeichnen.

Koch-Kurve in Java: private static void kochstep(TgFrame f, int n, float step) { if (n==0) { f.moveTurtle(step); } else { kochstep(f,n-1,step/3); f.turnTurtle(60); kochstep(f,n-1,step/3); f.turnTurtle(-120); }

Beispiel: Binär verzweigter Baum Ein Baum der Verzweigungstiefe n besteht aus einem Stamm, an dem jeweils im 45 Grad-Winkel nach rechts und links ein Teilbaum gleicher Struktur mit Verzweigungstiefe n-1 angesetzt wird.

Implementation in Java: private static void tree(TgFrame f, int depth, double step) { if (depth==1) { f.moveTurtle(step); f.moveTurtle(-step); } else { f.moveTurtle(step); f.turnTurtle(-45); tree(f,depth-1,step/1.75); f.turnTurtle(90); f.moveTurtle(-step); }

Backtracking: Hofstadters MU-Puzzle Backtracking-Verfahren als Probieren nach dem Tiefensuche-Prinzip Beispiel: MU-Puzzle von Hofstadter Gegeben ist folgendes Zeichensystem: Alphabet:     M, I, U Startwort:    "MI" Zielwort:      "MU" Operatoren (x,y stehen als Variablen für Teilstrings): (R1) xI  xIU (R2) Mx  Mxx (R3) xIIIy  xUy (R4) xUUy  xy Frage: Ist "MU" aus "MI" ableitbar?

2.5.3 Backtracking: Hofstadters MU-Puzzle Backtracking laut Informatik-Duden:   Backtracking bezeichnet ein Trial-and-Error-Verfahren, bei dem man versucht, eine Teillösung eines Problems inkrementell zu einer Gesamtlösung auszubauen. Falls in einer gewissen Situation ein weiterer Ausbau nicht mehr möglich ist (Sackgasse), müssen frühere Teilschritte zurückgenommen werden (daher Backtracking!). Zurücknehmen und erneutes Ausbauen wird solange wiederholt, bis eine Lösung gefunden wird oder bis man erkennt, dass im Rahmen der vorgegebenen Beschränkungen keine Lösung existiert. Im negativen Fall muss der (endliche) "Suchraum" vollständig exploriert werden, was i.d.R. exponentielle Komplexität bedeutet. Beispiel: Suche in einem Irrgarten.

Beispiel: MU-Puzzle von Hofstadter Gegeben ist folgendes Zeichensystem: Alphabet: M, I, U Startwort (z.B.): "MI" Zielwort (z.B.): "MU" Operatoren (x,y sind Variablen für Teilstrings): (R1) xI  xIU (R2) Mx  Mxx (R3) xIIIy  xUy (R4) xUUy  xy Frage: Ist "MU" aus "MI" ableitbar?

Allgemein: „Interpolationsproblem“ Gegeben: Zustandsmenge S, eine Menge von Operatoren O, d.h. jeder op aus O ist von der Art op: S  S, Startzustand s und Zielzustand z (beide aus S). Frage: Gibt es eine Operatorsequenz op1, ... opn mit         z = opn(opn-1( .... op1(s) ... )) ?

Ausgabe: eine Operatorsequenz (als Liste (java.Vector)) Parameter: s (aktueller Zustand), z (Zielzustand) und t (verbleibende Suchtiefe). Ausgabe: eine Operatorsequenz (als Liste (java.Vector)) muTrack(s, z: S, t: int)  Liste von O { wenn s = z dann rückgabe [ ]; /* leere Liste */ wenn t = 0 rückgabe null; /* "Fehlanzeige" */ res: Liste von O; /* späterer Ausgabeparameter */ n: S; /* nächster Folgezustand */ für alle op in O führe_aus { n := op(s); wenn nicht n = null /* d.h. Operator anwendbar */ dann { res := muTrack(n,z,t-1); wenn nicht res = null dann rückgabe mitErstem(op,res); } } rückgabe null; /* "Fehlanzeige" */ }

3 Speicherverfahren 3.1 Strukturierte Daten Definition (strukturiertes Datum): Ein strukturiertes Datum ist ein Tupel aus             ( Adresse a, Knoteninhalt k, Zeigerfeld z* ) wobei die Adresse ein Wort, der Knoteninhalt wiederum ein ordinaler oder strukturierter Typ und das Zeigerfeld eine Folge von Adressen oder Relationen zwischen Adressen ist, z.B: Adresse Knoteninhalt * *  ... *  Speicherung: injektive Abbildung von einer Datenstruktur bestehend aus Knoten mit Inhalten und Relationen (zu anderen Knoten der Datenstruktur) auf Adressen von Speicherzellen.

3.2 Beispiele für strukturierte Daten Lineare Listen, gekettet oder doppelt gekettet gespeichert. Speicherstruktur einer doppelt geketteten Liste:          Null Kopf 1: (k1, Null * , *  2) 2: (k2, 1  * , *  3) ... Ende n: (kn , n-1  * , *  Null) Null Durch 1: (k1, n  * , *  2) …… n: (kn , n-1  * , *  1) entsteht eine zirkuläre Liste.

Speicherung eines Arrays: Wir betrachten ein Array a [ 0..n1, 0..n2, ..., 0..nk] . Annahme: die Speicherung beginnt in e, und für jeden Knoten sind r Zellen notwendig. Dann wird das Element    a [ x1, x2, ..., xk ] an folgender Adresse abgelegt: e + r ( x1 (n2+ 1)(n3 + 1) … (nk+ 1) + x2 (n3+ 1) ... (nk + 1) + ... + xk-1 (nk + 1) + xk) Zahlenbeispiel: k = 3, n1 = 2, n2 = 3, n3 = 4, r = 5, e = 23. Dann wird das Element    a [ x1, x2, ..., xk ] an folgender Adresse abgelegt: e + r ( x1 (n2+ 1)(n3 + 1) + x2(n3 + 1) + x3 ), z.B. ist die Adresse des Elements    a [1, 3, 2] : 23 + 5 (1 • 4 • 5 + 3 • 5 + 2) = 208 

Beispiel: Im Fall n1 = n2 = … = nk =9 wird das Element a [x1, x2 , …, xk] an folgender Adresse abgelegt: e + r •( x1 •10k-1 + x2 • 10k-2 + … + xk-1 • 10 + xk ) = e + r • die Zahl mit der Dezimaldarstellung x1 x2 … xk . Die allgemeine Adressberechnung kann also als Verallgemeinerung der Dezimaldarstellung aufgefasst werden: mit möglicherweise verschiedenen Basen bei den verschiedenen Ziffern xi (Indizes des Elementes).

3.3 Verdichtete Speicherung Eine Menge von Daten kann verdichtet gespeichert werden, wenn fast alle Knoten den gleichen Wert k haben. In diesem Fall verzichtet man auf die Speicherung dieser Knoten und schließt aus ihrem Nichtauftreten, dass sie den Wert k haben. Dann muss jedoch jeder Knoten seine ursprüngliche Position mit sich führen, d.h. ki geht über in (i, ki). Beispiel: Gegeben sei eine lineare Liste (1, k1, *) (2, k2, * ) (3, k3, *) (4, k4, *)(5, k5, * ) (6, k6, *)(7, k7 , *)  ... für deren Elemente gilt: k = k2 = k4 = k5 = k6 = ... Verdichtete Speicherung: (1, k1, *)  (3, k3, *) (7, k7 , *)  ... 

3.4 Indizierte Speicherung Eine lineare Liste K = (k1, ..., kn)  kann in m disjunkte Teillisten aufgespalten werden. Man definiert eine Indexliste, die eine „Liste von Listen“ ist. In der Indexliste werden die Indizes mit einem Namen bzw. der Anzahl der Teillistenelemente und einem Zeiger auf den Beginn der Teillisten abgelegt. Beispiel:   d1     * k2, k2 * k5, k5 * k6, k6 * Null d2     * k1, k1 * Null, .... dm    * k3, k3 * k4, k4 * Null. Anwendung: bei Datenbanken und Betriebssystemen.

Beispiel: unter UNIX wird ein mehrfach indiziertes Speicherblocksystem verwendet. Plätze 0 bis 9: enthalten Adressen von 10 Blocks à 512 Bytes. Platz 10: enthält einen Zeiger auf eine Tabelle von 128 Blockadressen. Platz 11: enthält einen Zeiger auf eine Tabelle von 128 Indexblockadressen, die jeweils eine Tabelle von 128 Blockadressen betreffen (1282 Blockadressen). Platz 12: enthält einen Masterindexblock mit Adressen von 128 Indexblöcken à 128 Blockadressen, womit eine dreifache Indizierung erreicht ist (1283 Blockadressen). Insgesamt können so 2.113.674 Blöcke angesprochen werden.

3.5 Gestreute Speicherung Seien K = (k1, ..., kn) eine Datenmenge, S ein Speicherbereich mit Anfangsadresse e, w(k) ein Schlüssel zum Knoten k (für jeden Knoten k) (der Schlüssel ist üblicherweise eine Komponente oder eine Kombination von Komponenten des Knoteninhalts; wir nehmen an, dass verschiedene Knoten verschiedene Schlüssel haben) s eine Speicherfunktion vom Schlüsselraum der Daten in den Raum der Adressen. Wir sprechen von gestreuter Speicherung, wenn für jeden Knoten k gilt: Speicheradresse des Knotens k = e + s(w(k)). Das heißt, die Speicheradresse eines Knotens kann aus dem Schlüssel eines Knotens und daher aus dem Knoteninhalt berechnet werden!

Anforderungen an die Speicherfunktion s leicht zu berechnen, sollte nur vom Schlüsselraum, aber nicht von der Datenmenge abhängen, injektiv auf der Menge der vergebenen Schlüssel. Diese Forderungen sind wegen der Größe des Schlüsselraumes nicht gleichzeitig zu erfüllen: der Schlüsselraum, d.h. die Zahl der möglichen Schlüssel ist oft viel größer als die Zahl der zu vergebenden Speicheradressen. Injektivität auf dem ganzen Schlüsselraum ist dann nicht zu erreichen. Oft sind zwar nur relativ wenige Schlüssel tatsächlich vergeben. Welche, hängt aber von der Anwendung ab. Daher verzichtet man oft auf die Injektivität.

Kollision, Überlauf: Ist eine Speicherfunktion nicht injektiv, so können derselben Adresse mehrere Schlüssel zugeordnet werden.  Kollision oder Überlauf. Werden derselben Adresse m (m > 1) Schlüsselknoten zugeordnet, sprechen wir von einem Überlauf der Größe m-1.

Zur Vermeidung von Kollisionen wird eine weitere Anforderung an die Speicherfunktion gestellt: Möglichst gleichmäßige Verteilung der Schlüssel auf den Adressraum. Mehr noch: auch Regelmäßigkeiten bei den Schlüsseln sollten nicht auf den Adressraum übertragen werden. Beispiel: Variablennamen beginnen oft mit x, z.B: x1, xi. Hängt die Adresse nur vom ersten Zeichen ab, erhält man dann viele Kollisionen!

Beispiele 1. Beispiel für eine Speicherfunktion Divisionsrestverfahren: s(w(k)) := w(k) mod m wobei m eine Primzahl ist. Warum nicht z.B. m = 2k ? Dann würde die Adresse s(w(k)) nur von den letzten k Bits der Binärdarstellung von w(k) abhängen. Daraus folgt höhere Kollisionsgefahr (bei ungleichmäßiger Verteilung der letzten k Bits in den Schlüsseln)!

2. Beispiel für eine Speicherfunktion Ist w(k) der Schüssel von k, so kann s(w(k)) z.B. durch eine feste Anzahl und eine bestimmte Auswahl von Stellen in w2 gegeben sein: Hier: jeweils letzte und drittletzte Ziffer. w w2 s(w(k)) 723 522729 79 23 529 59 417 173889 89 233 54289 29 3 9 09 999 998001 01