Algorithmen & Programmierung Rekursive Funktionen (3)
Türme von Hanoi
Türme von Benares / Hanoi 1883 erfand der französische Mathematiker Lucas folgende Geschichte: Im Großen Tempel von Benares, unter dem Dom, der die Mitte der Welt markiert, ruht eine Messingplatte, in der drei Diamantnadeln befestigt sind, jede eine Elle hoch und so stark wie der Körper einer Biene. Bei der Erschaffung der Welt hat Brahma vierundsechzig Scheiben aus purem Gold auf eine der Nadeln gesteckt, wobei die größte Scheibe auf der Messingplatte ruht und die übrigen, immer kleiner werdend, eine auf der anderen. Tag und Nacht sind die Priester unablässig damit beschäftigt, den festgeschriebenen und unveränderlichen Gesetzen von Brahma folgend, die Scheiben von einer Diamantnadel auf eine andere zu setzen, wobei der oberste Priester nur jeweils eine Scheibe auf einmal umsetzen darf und zwar so, dass sich nie eine kleinere Scheibe unter einer größeren befindet. Sobald dereinst alle vierundsechzig Scheiben von der Nadel, auf die Brahma sie bei der Erschaffung der Welt gesetzt hat, auf eine der anderen Nadeln gebracht sein werden, zerfallen der Turm samt dem Tempel und allen Brahmanen zu Staub und die Welt wird mit einem Donnerschlag untergehen. 501
Türme von Hanoi Problembeschreibung A B C Ein Turm aus N beweglichen Teilen soll von Position A nach Position C bewegt werden Bedingungen / Voraussetzungen es stehen drei Ablagemöglichkeiten A, B und C für die Teile zur Verfügung die Größe eines Teils unterscheidet sich von der Größe aller anderen Teile ein Teil darf nur auf einem größeren Teil liegen, aber nicht umgekehrt zu einem Zeitpunkt darf nur ein Teil bewegt werden Nebenfrage Wieviel Schritte (Zeit) benötigt man für die Umschichtung? 502
Türme von Hanoi (N=3) A B C 503
Türme von Hanoi (N=3) A B C 504
Türme von Hanoi (N=3) A B C 505
Türme von Hanoi (N=3) A B C 506
Türme von Hanoi (N=3) A B C 507
Türme von Hanoi (N=3) A B C 508
Türme von Hanoi (N=3) A B C 509
Türme von Hanoi (N=3) A B C 510
Herleitung des Rekursionsprinzips N=3 Wir haben gezeigt, dass der gesamte Turm von A (via B) nach C geschoben werden kann. Wir haben dazu den Teilturm der Höhe 2, der sich auf der größten Scheibe befand nach B verschoben, anschließend die größte Scheibe nach C verschoben und schließlich den Teilturm von B nach C bewegt. N=4 Da ein Turm der Höhe 3 umgeschichtet werden kann, verschieben wir 1. den Teilturm der Höhe 3 von A nach B (via C) 2. die unterste Scheibe von A nach C 3. den Teilturm der Höhe 3 von B nach C (via A) 511
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 512
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 513
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 514
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 515
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 516
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 517
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 518
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 519
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 520
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 521
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 522
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 523
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 524
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 525
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 526
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 527
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 528
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 529
Türme von Hanoi (N=4) A B C 1. Verschiebe Teilturm der Höhe 3 von A nach B (via C) 2. Verschiebe die letzte Scheibe direkt von A nach C 3. Verschiebe Teilturm der Höhe 3 von B nach C (via A) 530
Herleitung des Rekursionsprinzips N=3 A B C 1. Verschieben des Teilturms der Höhe 2 von A nach B (via C) 2. Bewegen der untersten Scheibe von A nach C 3. Verschieben des Teilturms der Höhe 2 von B nach C (via A) N=4 1. Verschieben des Teilturms der Höhe 3 von A nach B (via C) 2. Bewegen der untersten Scheibe von A nach C 3. Verschieben des Teilturms der Höhe 3 von B nach C (via A) Für beliebige N 1. Verschieben des Teilturms der Höhe N 1 von A nach B (via C) 2. Bewegen der untersten Scheibe von A nach C 3. Verschieben des Teilturms der Höhe N 1 von B nach C (via A) Verschiebungen eines Turmes der Höhe 3 531
Ausgabe für Hanoi(3, 'A','B','C') Bewege Scheibe von A nach C Bewege Scheibe von A nach B Bewege Scheibe von C nach B }Hanoi(2,'A','C','B') Bewege Scheibe von A nach C Bewege Scheibe von B nach A Bewege Scheibe von B nach C Bewege Scheibe von A nach C } Hanoi(2,'B','A','C') 532
Anzahl der Umschichtungen Berechnung mit Induktion Wir haben für N=3 insgesamt sieben Scheiben verschoben (=2 N 1) Sei N=4: 1. Teilturm hat Höhe N 1, also 2 N 1 1 Bewegungen (7 Schritte) 2. Restscheibe wird direkt vom Ausgangs- zum Zielpunkt verschoben (1 Schritt) 3. Teilturm hat Höhe N 1, d.h. wieder 2 N 1 1 Bewegungen (7 Schritte) sind insgesamt 15 Schritte (2 (2 N 1 1) + 1) = 2 N 1 533
Backtracking
Backtracking Backtracking (Rückverfolgung) Backtracking ist eine Problemlösungsmethode, die auf folgendem Prinzip basiert: 1. Schaue, ob Du am Ziel bist. Wenn ja, dann endet der Algorithmus an dieser Stelle. 2. Wähle an der aktuellen Position einen noch nicht untersuchten Weg zum Ziel und gehe zu 1. 2.1. Falls es keine möglichen Wege gibt, dann gehe zurück zu der Position, die noch unerforschte Wege bietet und gehe zu 1. Führt ein Teilweg nicht zum Ziel, dann wird dieser Weg verworfen und an der Verzweigung des vorherigen Teilwegs weitergesucht. Backtracking und Rekursion Backtracking ist als Verfahren nicht notwendigerweise rekursiv, wird aber meist rekursiv implementiert. 535
Backtracking Beispiel Ein typisches Problem, das mit Backtracking gelöst werden kann, ist die Zielsuche in einem Labyrinth. Lösung mittels Backtracking 1. Schaue ob Du am Ziel bis. Wenn ja Algorithmus endet 2. Versuche zuerst geradeaus (oben), dann nach rechts, danach rückwärts (unten) und schließlich links mit Schritt 1 fortzufahren. Wegmarkierung Um sich nicht im Kreis zu drehen, ist es nötig, bereits besuchte Wege zu markieren. Von Wegpositionen, die garantiert nicht zum Ziel führen (weil alle von dieser Position startenden Teilsuchen erfolglos blieben) kann die Markierung entfernt werden. Dann bleibt am Ende nur der Weg übrig, der zum Ziel führt. 536
Backtracking Strategie: Oben Rechts Unten Links ############ # # # # # # # # #### # # ### # # # # # ###### # # # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Realisierung Das Labyrinth sei ein zweidimensionales char- Feld. Markierungen Leerzeichen kennzeichnen begehbare Wege Das #-Zeichen markiert Hindernisse. Buchstabe Z kennzeichnet das Ziel Ein Punkt (.) markiert besuchte Wege Startposition Eine beliebige begehbare Position in der Matrix. 537
Backtracking Strategie: Oben Rechts Unten Links ############ #. # # # # # # # #### # # ### # # # # # ###### # # # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Startposition sei (1,1): Der Algorithmus sucht im rekursiven Abstieg zunächst nach oben. Dies bleibt aufgrund der Begrenzung erfolglos. Es wird im rekursiven Abstieg nach rechts weitergesucht, was möglich ist. Danach wird wiederholt versucht nach oben zu gehen (was nicht möglich ist) und im Anschluss nach rechts (was möglich ist) bis auch der Weg nach rechts versperrt ist. 538
Backtracking Strategie: Oben Rechts Unten Links ############ #...# # # # # # # #### # # ### # # # # # ###### # # # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Jetzt ist nur ein rekursiver Abstieg nach unten möglich. Es wird solange rekursiv nach oben (nicht möglich), rechts (nicht möglich) und unten abgestiegen, bis auch der Weg nach unten versperrt ist. 539
Backtracking Strategie: Oben Rechts Unten Links ############ #...# # # # #. # # #### #. # ### # #. # # # ###### # # # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Es gibt für den rekursiven Abstieg keine weiteren Verzweigungsmöglichkeiten mehr, da alle Wege entweder blockiert (rechts, unten, links) oder bereits markiert (oben) sind. Deshalb werden beim rekursiven Aufstieg / Backtracking die letzten Entscheidungen solange zurückgenommen, bis es wieder eine unerforschte Alternative für den Abstieg der Rekursion gibt. 540
Backtracking Strategie: Oben Rechts Unten Links ############ #... # # # # # # # #### # # ### # # # # # ###### # # # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Die unerforschte Alternative bietet sich an der durch die rote Markierung dargestellten Position, denn ab dieser wurde noch nicht nach unten verzweigt. Da jeweils nach oben und rechts nicht verzweigt werden kann (da bereits besucht bzw. markiert oder blockiert), wird im rekursiven Abstieg der Weg nach unten verfolgt, bis wieder ein Hindernis den Weg versperrt. 541
Backtracking Strategie: Oben Rechts Unten Links ############ #... # # # #. # # # ####. # # ### #. # # # # ###### # # # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Da ab der rot markierten Position die Wege nach oben, rechts und unten versperrt bzw. bereits markiert sind, geht es im rekursiven Abstieg nach links weiter. 542
Backtracking Strategie: Oben Rechts Unten Links ############ #... # # # #. # # # ####. # # ### #....# # # # ###### # # # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Analog der bisherigen Verfahrensweise geht es im rekursiven Abstieg erst nach unten weiter (da oben und rechts gesperrt bzw. markiert sind) und dann nach rechts. 543
Backtracking Strategie: Oben Rechts Unten Links ############ #... # # # #. # # # ####. # # ### #...# # # #. ###### # #... # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ An der rot markierten Position gibt es für den rekursiven Abstieg keine weitere Verzweigungsmöglichkeit mehr, da alle Wege entweder versperrt oder markiert sind Sackgasse. Deshalb muss diese Teillösung wieder verworfen werden. Im Rekursionsaufstieg / Backtracking wird bis zu der Position zurückgegangen, die für den Rekursionsabstieg noch eine unerforschte Alternative bietet. 544
Backtracking Strategie: Oben Rechts Unten Links ############ #... # # # #. # # # ####. # # ### #...# # # #. ###### # #... # Z # # ## ## # # ## ## ## # # ## ## ## # # ## # ############ Ab der rot markierten Position kann im rekursiven Abstieg wieder verzweigt werden: zunächst mehrere Male nach unten dann wiederholt nach rechts schließlich mehrmals nach oben und noch einmal nach rechts 545
Backtracking Strategie: Oben Rechts Unten Links ############ #... # # # #. # # # ####. # # ### #...# # # #. ###### # #... #.Z # # ##. ##. # # ## ##. ##. # # ## ##. ##. # # ##...# ############ Das Ziel wurde erreicht. 546
Backtracking Strategie: Unten Rechts Oben Links ############ #. # #. # # # # #...#### # # ###. # # # #..# ###### #. #... #. Z #..#. ##. ##. # #. ##. ##. ##. # #. ##. ##. ##. # #...##...# ############ Achtung Verändert man die Suchstrategie, z.b. durch Ändern der Reihenfolge, welche Richtung zuerst untersucht wird, kann es zu anderen Ergebnissen kommen (falls mehrere Wege aus dem Labyrinth existieren). Beispiel Vertauschen wir in der Suchreihenfolge oben mit unten, dann findet der Algorithmus einen anderen Weg zum Ziel. 547
Das Acht-Damen-Problem
Acht-Damen-Problem Problembeschreibung Beim Schach darf sich die Spielfigur Dame horizontal, vertikal und diagonal auf dem 8x8-Felder großen Spielfeld bewegen, d.h. dass eine Dame jede (gegnerische) Spielfigur bedroht, die sich horizontal, vertikal oder diagonal von ihr aus erreichen lässt. Eine interessante Aufgabe besteht darin, acht Damen so auf dem Spielfeld zu platzieren, dass sie sich nicht gegenseitig bedrohen. Eine mögliche Lösung ist nebenstehend abgebildet. 549
Verallgemeinerung Wie können N Damen auf einem NxN großen Schachbrett angeordnet werden, so dass sie sich nicht bedrohen? Lösungsidee Wir nutzen die Tatsache aus, dass sich in einer Reihe nur eine Dame befinden kann und ordnen jede Dame auf einer der N möglichen Felder einer Reihe so an, dass sie von keiner anderen Dame bedroht wird: 1. wir setzen die erste Dame an eine der N Positionen in Reihe 1 2. wir setzen die zweite Dame an eine der N Positionen in Reihe 2... N. wir setzen die n-te Dame an eine der N Positionen in Reihe N Falls sich in einem der N Schritte eine Bedohungssituation ergibt, wählen wir eine andere mögliche Position der aktuellen Reihe aus Falls sich keine Positionierungsmöglichkeit einer Dame in der aktuellen Reihe ergibt, wird mittels Backtracking in die Reihe zurückgesprungen, in der es noch Wahlmöglichkeiten gibt. 550
Beispiel: Vier-Damen-Problem Backtracking nötig 551
Beispiel: Vier-Damen-Problem Backtracking nötig Backtracking nötig 552
Beispiel: Vier-Damen-Problem Backtracking nötig Backtracking nötig 553
Beispiel: Vier-Damen-Problem Gültige Anordnung gefunden! 554
N-Damen-Problem Variante Eine Variante des N-Damen-Problems besteht darin, die Anzahl möglicher Anordnungen von N Damen auf einem NxN-Spielfeld herauszufinden: N Anzahl Lösungen 1 1 2 0 3 0 4 2 5 10 6 4 7 40 8 92 9 352 10 724 555
Zusammenfassung
Anwendung rekursiver Algorithmen Probleme die von Natur aus rekursiv definiert sind, z.b. die Erzeugung und Erkennung formaler Sprachen Probleme deren Unterprobleme beim Top-Down-Entwurf die selbe Komplexität wie das Ausgangsproblem aufweisen Probleme die auf einer umgekehrten Verarbeitungsreihenfolge basieren Probleme, bei denen die Größe von Ergebnis bzw. Zwischenergebnissen im Vorhinein nicht bekannt ist Probleme, die auf rekursiven Datenstrukturen basieren Vorlesung Datenstrukturen 557
Rekursion vs. Iteration Realisierung Rekursion (Funktionsmodell) Rekursiver Aufruf einer Funktion Iteration (Zustandsmodell) Durchführen der Anweisungsfolge eines Iterationsschrittes Steuerung Die Parameter einer Funktion werden in der Funktion selbst modifiziert und auf Erreichen einer Abbruchbedingung getestet Die Steuerung der Anzahl an Iterationsschritten erfolgt mit Hilfe von Zählvariablen Speicherung von Daten Die Speicherung eines verarbeiteten Elements erfolgt implizit durch automatische Sicherung der Funktionsparameter auf dem Stack Ein zu verarbeitendes Element bzw. eine Elementefolge muss explizit gespeichert werden (z.b. in einem Feld) Zugriff auf Daten Der Zugriff auf Elemente einer Folge ist begrenzt auf die aktuelle Komponente der gerade aktiven Funktionsinstanz Der Zugriff auf Elemente einer Folge kann wahlfrei erfolgen 558
Rekursion - Bewertung Vorteile Insbesondere bei rekursiv definierten Problemen sind rekursive Implementierungen wesentlich kürzer, einfacher, verständlicher und mathematisch eleganter als iterative Lösungen. Rekursive Funktionen können variabel große Datenmengen verarbeiten und speichern. Nachteile Fazit Aufgrund der temporären Sicherung aller lokalen Variablen und der Einträge der Parameterliste für jede aufgerufene Funktionsinstanz besteht ein hoher Speicherbedarf. Unter Umständen kann bei sehr vielen rekursiven Funktionsaufrufen sogar der Stack überlaufen. Wegen des aufgrund der temporären Sicherung entstehenden Overheads sind rekursive Lösungen meist wesentlich weniger effizient als vergleichbare iterative Lösungen. Rekursion ist (nur) eine von mehreren möglichen Problemlösungsstrategien. Wenn einfache iterative Lösungen für ein Problem existieren, so sind diese i.d.r. zu bevorzugen. 559
Ende der Vorlesung