Teil von  SELFPHP   Teil von  Praxisbuch  Teil von  Sprachelemente und Syntax  Teil von  Funktionen und Prozeduren
Letztes Update: 04.09.2007 20:49:50

Navigation

Seite Startseite
Seite Aktuelles
Seite Seite News*
Seite Seite Pressemitteilungen*
Seite SELFPHP
Seite Seite Über SELFPHP
Seite Seite Werbung
Seite Seite Kontakt
Seite Seite Unsere Banner
Seite Seite Impressum
Seite Qozido
Seite Seite Diving Edition
Seite Seite Snorkeling Edition
Seite SELFPHP Dokumentation
Seite Seite PHP-Skripte
Seite Seite PHP Befehlsreferenz
Seite Seite PHP 5 Praxisbuch
Seite Seite PHP Code Snippets
Seite Seite SELFPHP in Buchform
Seite Anbieterverzeichnis
Seite Seite Globale Branchen
Seite Seite Webhosting/Server
Seite Services
Seite Seite Forum*
Seite Seite RSS-Feeds*
Seite Seite Downloads*
Seite Seite Gratis-Video-Lektionen*
Seite Seite SELFPHP auf Heft-CD*
Seite Seite Newsletter*
Seite Internet Security
 sponsored by  
Seite Stellenangebote*
Sedo - Bei uns wird PHP großgeschrieben
Seite Premium-Partner   
Webhosting/Serverlösungen
Seite Produktempfehlung   
Seite Seite SteadyBackup

 
* Link führt ins Internet


Anbieterverzeichnis
Informieren Sie sich über die Unternehmen in unserem Anbieterverzeichnis!  
 


SELFPHP Forum
Fragen rund um die Themen PHP? In über 100.000 Beiträgen finden Sie sicher die passende Antwort!*  


Newsletter
Abonnieren Sie hier den kostenlosen SELFPHP Newsletter!*

Vorname: 
Name:
E-Mail:
 




 

Rekursive Funktionen




Sie werden nun noch eine weitere Methode kennenlernen, Funktionen zu verwenden. Es handelt sich dabei um rekursive Funktionen. Dies ist eine Funktion, die sich selbst aufruft. Rekursive Funktionen werden vor allem dort eingesetzt, wo man nicht genau vorherbestimmen kann, wie verschachtelt eine Datenstruktur ist.


Rekursion allgemein

Unter einer Rekursion versteht man die Definition eines Programms, einer Funktion oder eines Verfahrens durch sich selbst. Rekursive Darstellungen sind im Allgemeinen kürzer und leichter verständlich als andere Darstellungen, da sie die charakteristischen Eigenschaften einer Funktion betonen.

Ein Algorithmus heißt rekursiv, wenn er Abschnitte enthält, die sich selbst aufrufen. Er heißt iterativ, wenn bestimmte Abschnitte des Algorithmus innerhalb einer einzigen Ausführung des Algorithmus mehrfach durchlaufen werden. Iteration und Rekursion können oft alternativ in Programmen eingesetzt werden, da man jede Iteration in eine Rekursion umformen kann, und umgekehrt. In der Praxis liegt jedoch oftmals die iterative oder die rekursive Lösung auf der Hand und die jeweils alternative Form ist gar nicht so leicht zu bestimmen.

Hinweis: Programmtechnisch läuft eine Iteration auf eine Schleife, eine Rekursion auf den Aufruf einer Methode durch sich selbst hinaus.

Fallbeispiel

Nehmen Sie einen Papierstreifen und versuchen Sie ihn so zu falten, dass sieben genau gleich große Teile entstehen. Dabei dürfen Sie kein Lineal oder sonst ein Hilfsmittel verwenden. Sie werden feststellen, das die Aufgabe gar nicht so einfach ist!

Wenn Sie statt sieben jedoch acht Teile machen, wird es plötzlich einfach: Einmal in der Mitte falten, dann nochmals falten ...

Genau das ist das Prinzip der Rekursion: Ein Problem wird auf ein »kleineres« Problem zurückgeführt, das wiederum nach demselben Verfahren bearbeitet wird. Rekursion ist eine wichtige algorithmische Technik.

Am obigen Beispiel haben Sie auch gesehen, dass die Lösung einer Aufgabe, wenn sie mit Rekursion möglich ist, sehr einfach gelöst werden kann. Hier nun zwei rekursive Fallbeispiele.


Fakultät einer Zahl n (n!) rekursiv

Bei der Berechnung der Fakultätsfunktion geht man aus von der Definition der Fakultät:
0! = 1
n! = 1 * 2 * 3 * ... * n für n>0

Man beginnt bei den kleinen Zahlen. Der Wert von O! ist 1, der Wert von 1! ist 0!*1, der Wert von 2! ist 1!*2, der Wert von 3! ist 2!*3 usw.

Nimmt man eine Schleifenvariable $i, die von 1 bis n durchgezählt wird, so muss innerhalb der Schleife lediglich der Wert der Fakultät vom vorhergehenden Schleifendurchlauf mit dem Wert der Schleifenvariablen multipliziert werden.

Lösung 1 (iterativ)

<?php
function fak($n) {
  $resultat = 1;
  for ($i=1; $i<=$n; $i++) {
    $resultat = $i*$resultat;
  }
  return $resultat;
}
echo fak(1) . "<br>";
echo fak(2) . "<br>";
echo fak(3) . "<br>";
echo fak(4) . "<br>";
?>

Ausgabe
1
2
6
24

Bei der rekursiven Berechnung der Fakultätsfunktion geht man ebenfalls von der Definition der Fakultät aus, beginnt jedoch nicht bei den kleinen Zahlen, sondern bei den großen Zahlen und läuft dann zu den kleinen Zahlen zurück (recurrere = lat. zurücklaufen).
n! = 1 * 2 * 3 * ... * n für n>0
0! = 1

Im Gegensatz zur Iteration schaut man jetzt auf die Funktion f(n) und versucht, diese Funktion durch sich selbst, aber mit anderen Aufrufparametern darzustellen.


Die mathematische Analyse ist hier ziemlich leicht, denn man sieht sofort, dass

f(n) = n * f(n-1)

ist. Damit hat man das Rekursionsprinzip bereits gefunden. Die Rekursion darf jedoch nicht ewig andauern, sie muss durch ein Abbruchkriterium angehalten werden. Dies ist die Bedingung 0!=1.

Lösung 2 (rekursiv)

<?php
function fak($n){
  if ($n==0) {
    return 1;
  } else {
    return $n*fak($n-1);
  }
}

echo fak(1) . "<br>";
echo fak(2) . "<br>";
echo fak(3) . "<br>";
echo fak(4) . "<br>";
?>

Ausgabe
1
2
6
24

Der else-Zweig wird angesprungen, wenn die Abbruchbedingung nicht erreicht wird. Hier ruft die Methode sich selbst wieder auf. Hierbei ist zu beachten, dass die Anweisung, die die Methode aufruft, noch gar nicht abgearbeitet werden kann, solange die aufgerufene Methode kein Ergebnis zurückliefert.

Der if-Zweig wird angesprungen, wenn die Abbruchbedingung erreicht ist.

Um Ihnen die Analyse zu vereinfachen, habe ich die rekursive Lösung etwas angepasst.
<?php
function fak($n){
  //Aufruf
  echo "Eintritt mit $n<br>";
  if ($n==0) {
    return 1;
  } else {
    $ergebnis = $n*fak($n-1);
    // Rücksprung
    echo "Austritt mit $n: $ergebnis<br>";
    return $ergebnis;
  }
}

fak(4);
?>

Ausgabe
Eintritt mit 4
Eintritt mit 3
Eintritt mit 2
Eintritt mit 1
Eintritt mit 0
Austritt mit 1: 1
Austritt mit 2: 2
Austritt mit 3: 6
Austritt mit 4: 24

Zu jedem Aufruf gehört auch genau ein Rücksprung! Sie können dies beim Programmablauf mithilfe der eingefügten Ausgabezeilen nachvollziehen.

Man beachte die Anzahl der Aufrufe. Im iterativen Fall wird die Methode ein einziges Mal aufgerufen und im Schleifenkörper n Mal durchlaufen. Bei der rekursiven Berechnung wird die Methode n+1 Mal aufgerufen. Dabei muss jedes Mal Speicherplatz auf dem Stack reserviert werden. Da Parameter als lokale Variablen kopiert werden, wird auch dabei Speicherplatz verbraucht. Bei Rekursionen ist daher unbedingt darauf zu achten, dass die Abbruchbedingung bzw. das Rekursionsende korrekt implementiert wurde.


Türme von Hanoi

Ein Turm aus n verschieden großen Scheiben soll mit möglichst wenig Zügen (Umsetzungen) vom Startplatz S auf den Zielplatz Z transportiert werden. Ein dritter Platz steht als Hilfsplatz H zur Verfügung. Dabei gelten die folgenden Spielregeln:
  • Jeder Zug besteht darin, eine Scheibe zu bewegen.

  • Niemals darf eine größere Schiebe über einer kleineren Scheibe zu liegen kommen.




Bild 3.9: Türme von Hanoi


Schlüsselprinzip: Rekursion

Wenn wir das Problem in einem etwas einfacher gelagerten Fall lösen können, dann kann man diese Lösung auch für den schwierigeren Fall verwenden.
2 Scheiben:
- übertrage den Turm mit 1 Scheibe vom Start- auf den Hilfsplatz
- bewege die Scheibe 2 vom Start- auf den Zielplatz
- übertrage den Turm mit 1 Scheibe vom Hilfs- auf den Zielplatz
3 Scheiben:
- übertrage den Turm mit 2 Scheiben vom Start- auf den Hilfsplatz
- bewege die Scheibe 3 vom Start- auf den Zielplatz
- übertrage den Turm mit 2 Scheiben vom Hilfs- auf den Zielplatz
...
n Scheiben:
- übertrage den Turm mit n-1 Scheiben vom Start- auf den Hilfsplatz
- bewege die Scheibe n vom Start- auf den Zielplatz
- übertrage den Turm mit n-1 Scheiben vom Hilfs- auf den Zielplatz


Die Baumstruktur beim Aufrufen der Syntax



Bild 3.10: Ablauf der Rekursion

Lösung
<?php
function setzeTurm($n, $start, $ziel, $hilf) {
  if ($n>0) {
    setzeTurm ($n-1, $start, $hilf, $ziel);
    echo("Bewege Scheibe $n vom $start-Platz zum $ziel-Platz.<br>");
    setzeTurm ($n-1, $hilf, $ziel, $start);
  }
}

setzeTurm (3,'Start','Ziel','Hilfsplatz');
?>

Ausgabe
Bewege Scheibe 1 vom Start-Platz zum Ziel-Platz.
Bewege Scheibe 2 vom Start-Platz zum Hilfsplatz-Platz.
Bewege Scheibe 1 vom Ziel-Platz zum Hilfsplatz-Platz.
Bewege Scheibe 3 vom Start-Platz zum Ziel-Platz.
Bewege Scheibe 1 vom Hilfsplatz-Platz zum Start-Platz.
Bewege Scheibe 2 vom Hilfsplatz-Platz zum Ziel-Platz.
Bewege Scheibe 1 vom Start-Platz zum Ziel-Platz.

Weitere Beispiele für rekursive Probleme sind:
  • Wege aus einem Labyrinth
  • Sortierverfahren
  • Szierpinski-Dreiecke
  • Baum des Pythagoras
  • Kockkurven
  • Julia- und Mandelbrotmengen
  • Logistisches Wachstum
  • Fibonacchi-Folge
  • Springer-Problem
  • 8-Damen-Problem



 




 sponsored by

Sedo - Bei uns wird PHP großgeschrieben


hostfactory.ch - OptimaNet Schweiz AG


HighText iBusiness


VERIO - An NTT Communications Company


Webspace-Verkauf.de


video2brain




 Premium-Partner
 Webhosting/Serverlösungen

BPI-Systeme


Premium-Partner Pixel X


Premium-Partner First Colo


Premium-Partner dogado Internet




Qozido


© 2001-2009 E-Mail SELFPHP - Damir Enseleit, info@selfphp.deImpressumKontakt