Benutzer-Werkzeuge

Webseiten-Werkzeuge


schule:rekursion

Rekursion

Die Rekursion beschreibt in der Programmierung das Phänomen, wenn eine Methode sich selbst aufruft.

Ein Algorithmus ist rekursiv, wenn er mit Hilfe einfacher Varianten von sich selbst beschrieben wird.

loese(<Problem>):
   ...
   loese(<einfacheres Problem>)
   ...

Das sieht zunächst seltsam aus, kann sich aber in vielen Situationen als nützlich erweisen.

Allgemeiner Aufbau

Eine rekursive Funktion oder Methode ist häufig nach einem ganz bestimmten Muster aufgebaut.

REKURSIVE_METHODE(<Problem>):
  if <das Problem ist leicht>:
    <löse das Problem>
  else:
    <mache das Problem leichter>
    REKURSIVE_METHODE(<leichteres Problem>)

Jeder rekursive Algorithmus muss eine Abbruchbedingung enthalten.

Beispiel: Anzahl Elemente einer Liste

Ein Beispiel soll dies veranschaulichen: Wir wollen die Anzahl der Elemente in einer Liste ermitteln. Ein gewöhnliches iteratives Verfahren könnte wie folgt aussehen.

anzahl(liste):
  anzahl = 0
  for element in liste:
    anzahl = anzahl + 1
 
  return anzahl

Ein rekursiver Algorithmus würde das Problem wie folgt lösen:

anzahl(liste):
  if liste ist leer:
    return 0
 
  else:
    liste_kleiner = liste.entferneErstesElement()
    return 1 + anzahl(liste_kleiner)

Übung Ausgabe

Alle Elemente einer Liste sollen mit der Methode ausgeben(liste) ausgegeben werden. Nutze ein rekursives Verfahren. Überlege zunächst, für welche Liste das Problem leicht lösbar ist.

>>> ausgeben([1,2,3])
1
2
3
>>> ausgeben([1])
1

Übung rekursive Suche

Wie sieht ein rekursiver Algorithmus suche(n, liste) aus, der ein Element in einer Liste sucht und True oder False zurückgibt, wenn das Element in der Liste vorhanden ist oder nicht?

>>> suche(1, [1,2,3])
True

>>> suche(2, [1,2,3])
True

>>> suche(3, [1,2,3])
True

>>> suche(4, [1,2,3])
False

Übung Filtern

Schreibe einen rekursiven Algorithmus, der alle geraden Zahlen aus einer Liste zurück gibt.

>>> gerade([1,2,3])
[2]

>>> gerade([1,2,3,4])
[4, 2]

>>> gerade([1,3,4])
[4]

>>> gerade([])
[]

Übung Streckenalgorithmus

In den Materialien findest du Informationen darüber, wie eine Strecke zwischen zwei Punkten A und B mit einem rekursiven Verfahren auf dem Bildschirm ausgegeben werden kann.

Wie sieht der einfache Fall aus?

Vervollständige den folgenden Algorithmus zum Zeichnen einer Strecke.

from tkinter import *
 
class App:
    def __init__(self):
        fenster = Tk()
 
        self.canv = Canvas(fenster, width=200, height=200)
        self.canv.pack()
 
        self.strecke(10, 10, 150, 180)
        fenster.mainloop()
 
    def markiere(self, x, y):
        self.canv.create_rectangle(x,y,x+1,y+1)
 
 
    def strecke(self, ax, ay, bx, by):
        # Hier muss eine Strecke rekursiv gezeichnet werden
        # if Punkte a und b benachbart:
        #   zeichne Pixel a und b
        # else:
        #   berechne mittelpunkt m
        #   zeichne Strecke von a bis m
        #   zeichne Strecke von m bis b
        pass
 
app = App()

Übung Kochkurve

Eine weitere Anwendung von Rekursion findet sich in selbst-ähnlichen Kurven aus der Mathematik und der Natur. Die Koch-Kurve ist eine solche Figur, die mit Turtle-Grafiken erstellt werden kann.

Verwende die folgende Vorlage und zeichne damit eine Kochkurve.

kockurve.py
import turtle
 
"""
Die Turtle kann mit folgenden Befehlen bewegt werden:
 
tutle.forward(distanz) bewegt die Schildkröte in Blickrichtung
turtle.right(winkel) dreht die Schildkröte nach rechts.
tirtle.left(winkel) dreht die Schildkröte nach links.
"""
 
def kochkurve(laenge, tiefe):
    """Zeichnet eine Kochkurve.
    laenge beschreibt die Länge des aktuellen Streckenabschnitts
    tiefe steht für die Rekursionstiefe."""
    if tiefe == 0:
        """Gehe nach vorn."""
    else:
        """Zeichne eine Kochkurve, drehe nach links, zeichne wieder eine Kurve, 
        drehe nach rechts, zeichne erneut, drehe nach links und zeichne den Schluss. 
        _/\_ """
 
# Starte das Programm
turtle.reset()
turtle.speed(5)
 
kochkurve(300, 2)

Übung Grundrechenarten

Auch die Grundrechenarten + und * lassen sich rekursiv beschreiben:

  add(0, m) = 0 + m = m
  add(n, m) = n + m = ((n-1) + m) +1
  mult(0, m) = 0 * m = 0
  mult(n, m) = n *m = (n-1)*m + m = add( mult(n-1, m), m)
  

Programmiere die Methoden add und mult.

Übung Türme von Hanoi

Unterschiedlich große Scheiben sind der Größe nach auf einem Stab platziert. Es gibt drei Stäbe A, B und C. Alle Scheiben müssen von Stab A nach C bewegt werden. Es darf immer nur eine Scheibe bewegt werden. Eine Scheibe darf nur auf eine größeren Scheibe platziert werden.

Am besten probierst du das Spiel einmal selbst aus.

Ein möglicher Algorithmus, um das Problem zu lösen.

bewege(Zahl i, Stab a, Stab b, Stab c)
    if i == 0:
       <mache nichts>
    else:
       bewege(i-1, a, c, b)
       verschiebe oberste Scheibe von a nach c
       bewege(i-1, b, a, c)

Ein Video beschreibt den Zusammenhang zwischen Binärzahlen und den Zügen der Scheiben des Hanoi-Spiels.

Übung Flachklopfen

Die Methode flach_klopfen nimmt eine Liste aus Listen entgegen und gibt eine flache Liste zurück, die nur noch die Elemente der Einzellisten enthält. Diese Listen könnten z.B. Verzeichnisse und Dateien in diesen Verzeichnissen in einem Dateisystem darstellen. Jeder Liste innerhalb einer Liste steht dann für ein Unterverzeichnis.

>>> flach_klopfen([1,2,3])
[1,2,3]

>>> flach_klopfen([1,[2],3])
[1,2,3]

>>> flach_klopfen([[],1,2,3]))
[1,2,3]

>>> flach_klopfen([1,[2,[3]]])
[1,2,3]

>>> flach_klopfen([1,[], [2, 3],[]])
[1,2,3]

Übung umdrehen

Die Methode umdrehen nimmt eine Liste entgegen und dreht diese Liste um, so dass anschließend alle Elemente in umgedrehter Reihenfolge in der Liste auftauchen.

>>> umdrehen([])
[]
>>> umdrehen([1,2,3])
[3, 2, 1]

Live Coding mit Fluxus

Die Programmierumgebung Fluxus kann für das Live-Coding verwendet werden und nutzt in der Programmiersprache rekursive Mechanismen.

Probleme rekursiver Algorithmen

Rekursive Algorithmen sind häufig elegant und kurz, manchmal aber auch schwer zu verstehen. Nicht immer sind sie das richtige Mittel der Wahl, obwohl manche Programmiersprachen vollständig auf Rekursion setzen.

  • Hoher Speicherplatzbedarf - Jeder Aufruf benötigt Speicherplatz für lokale Variablen
  • Unendliche Rekursion - Wenn man nicht aufpasst, enden die rekursiven niemals.

Rekursive Abkürzungen

Auch in anderen Gebieten der Informatik hat sich die Rekursion etabliert. So gibt es rekursive Abkürzungen:

  • PHP (PHP Hypertext Preprocessor)
  • LAME (LAME Ain’t an Mp3 Encoder)
  • WINE (WINE Is Not an Emulator)
  • YAML (YAML Ain't Markup Language)
schule/rekursion.txt · Zuletzt geändert: 12.12.2017 19:10 von Marco Bakera