1 / 28

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

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 .

iniko
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 2.5    Verzweigte Rekursion und Backtracking-Verfahren2.5.1    Türme von Hanoi

  2. 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!

  3. 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).

  4. 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"); } }

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

  6. 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.

  7. 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); kochstep(f,n-1,step/3); f.turnTurtle(60); kochstep(f,n-1,step/3); } }

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

  9. 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); tree(f,depth-1,step/1.75); f.turnTurtle(-45); f.moveTurtle(-step); } }

  10. 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?

  11. 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.

  12. 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?

  13. 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 undZielzustand z (beideaus S). Frage: Gibt es eine Operatorsequenz op1, ... opn mit       z = opn(opn-1( .... op1(s) ... )) ?

  14. 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" */ }

  15. 3    Speicherverfahren3.1    Strukturierte Daten Definition (strukturiertes Datum): Einstrukturiertes 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.

  16. 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.

  17. 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 

  18. 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).

  19. 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 , *)  ... 

  20. 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.

  21. 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.

  22. 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!

  23. 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.

  24. 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ößem-1.

  25. 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!

  26. Beispiele 1. Beispiel für eine Speicherfunktion Divisionsrestverfahren:s(w(k)) := w(k) mod mwobei 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)!

  27. 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.

More Related