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

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

Embed Size (px)

Citation preview

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

1

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

Page 2: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.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!

Page 3: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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

Page 4: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

4

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

Implementation in Java

Page 5: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

5

2.5.2    Erzeugung fraktaler Muster durch

verzweigt rekursive Turtle-Programme

Beispiel: Koch-Kurve (Schneeflockenkurve)

Page 6: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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.

Page 7: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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); } }

Page 8: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

8

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.

Page 9: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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);

}

}

Page 10: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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 xyFrage: Ist "MU" aus "MI" ableitbar?

Page 11: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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.

Page 12: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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 xyFrage: Ist "MU" aus "MI" ableitbar?

Page 13: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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 und Zielzustand z (beide aus S).

Frage: Gibt es eine Operatorsequenz

op1, ... opn mit  

      z = opn(opn-1( .... op1(s) ... )) ?

Page 14: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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

Page 15: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

15

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

Page 16: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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.

Page 17: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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 

Page 18: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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

Page 19: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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

Page 20: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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.

Page 21: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

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.

Page 22: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

22

Page 23: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

23

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!

Page 24: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

24

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.

Page 25: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

25

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.

Page 26: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

26

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!

Page 27: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

27

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)!

Page 28: 1 2.5 Verzweigte Rekursion und Backtracking-Verfahren 2.5.1 Türme von Hanoi

28

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