Teil von  SELFPHP   Teil von  Praxisbuch  Teil von  Funktionen und Prozeduren
Letztes Update: 16.08.2005 17:53:45


Navigation

Seite News *

Seite Startseite
Seite Über SELFPHP
Seite Werbung
Seite Kontakt
Seite Forum *
Seite PHP-Skripte
Seite PHP Befehlsreferenz
Seite PHP5 Praxisbuch
Seite Gratis-Videolektionen*
Seite Download *
Seite SELFPHP Banner *
Seite SELFPHP in Buchform
Seite Newsletter *
Seite Impressum

Seite Anbieterverzeichnis

 
* 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 79.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 Methode kennen lernen 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 Eingenschaften 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 mehfrfach 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 dazu alternative Form ist gar nicht so leicht zu bestimmen.

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



Fallbeispiel

Nehmen Sie einen Papierstreifen und versuchen Sie ihn so zu falten, dass sieben genau gleich grosse 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 Fallbeispiel.


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 vohergehenden 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 Aurfufparametern, 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 haben wir 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 mit Hilfe 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 jedesmal 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.


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:

- uebertrage den Turm mit 1 Scheibe vom Start- auf den Hilfsplatz
- bewege die Scheibe 2 vom Start- auf den Zielplatz
- uebertrage den Turm mit 1 Scheibe vom Hilfs- auf den Zielplatz


3 Scheiben:

- uebertrage den Turm mit 2 Scheiben vom Start- auf den Hilfsplatz
- bewege die Scheibe 3 vom Start- auf den Zielplatz
- uebertrage den Turm mit 2 Scheiben vom Hilfs- auf den Zielplatz

...

n Scheiben:

- uebertrage den Turm mit n-1 Scheiben vom Start- auf den Hilfsplatz
- bewege die Scheibe n vom Start- auf den Zielplatz
- uebertrage den Turm mit n-1 Scheiben vom Hilfs- auf den Zielplatz


Syntax der Aufrufe: (Beachten sie die Baumstruktur)


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


 


Variablenfunktionen
 




 sponsored by

Host Europe


HighText iBusiness


Host Europe




© 2001-2006 E-Mail SELFPHP - Damir Enseleit, info@selfphp.deImpressumKontakt
© 2005-2006 E-Mail PHP5 Praxisbuch - Matthias Kannengiesser, m.kannengiesser@selfphp.de