Andreas Klatt: Frage zum Ablauf einer rekursiven Funktion

Moin,

ich habe eine rekursive Funktion, die mir eine Ausgabe beschert, die mit Sicherheit seine Richtigkeit hat, die ich aber nicht verstehe.
Hauptsächlich geht es darum, was mit Programmcode passiert, der hinter dem Funktionsaufruf innerhalb der Funktion steht. Wann wird der mit welchen Werten ausgeführt?
Um mir das Problem zu verdeutlichen, habe ich eine kleine Funktion geschrieben, die mit <body onLoad=welcome(4)> aufgerufen wird:

function welcome(i)
  {
   if(i == 0)
   {
   }
   else
   {
    document.write("Willkommen A " + i + "<br>");
    i--;
    welcome(i);
    document.write("Willkommen B " + i + "<br>");
   }
  }

Als Ausgabe erhalte ich:
Willkommen A 4
Willkommen A 3
Willkommen A 2
Willkommen A 1
Willkommen B 0
Willkommen B 1
Willkommen B 2
Willkommen B 3

Die ersten vier Zeilen verstehe ich.
Aber warum wird danach mit i=0 "Willkommen B 0" ausgegeben, wo doch bei i == 0 gar nicht in die else-Schleife gesprungen werden soll. Und: Warum wird danach die Zeile mehrmals ausgegeben?
Ich kann mir das nur so erklären, dass das Programm alle Werte auf einen FIFO-Stack zwischenspeichert und auf die folgenden Zeilen loslässt, sobald der rekursive Programmaufruf sein Ende gefunden hat. Aber müsste i nicht wieder mit 3 beginnen (da, wo es aufgehört hatte)?, also:

Willkommen A 4
Willkommen A 3
Willkommen A 2
Willkommen A 1
Willkommen B 3
Willkommen B 2
Willkommen B 1
(Willkommen B 0)?

Vielen Dank für jeden Hinweis,
Gruß

Andreas Klatt.

  1. Also die Funktion stimmt mit der Ausgabe überein.

    Nur weil sich die function in sich selbst nochmal aufruft heisst das nicht das der Rest der function nicht mehr abgearbeitet wird.

    Ich versuch das hier mal zu verdeutlichen:

    welcome(4) {
      write(Willkommen A 4)
      4-1=3
      welcome(3) {
        write(Willkommen A 4)
        3-1=2
        welcome(2) {
          write(Willkommen A 4)
          2-1=1
          welcome(1) {
            write(Willkommen A 4)
            1-1=0
            welcome(0) {
              }
            write(Willkommen B 0)
          }
          write(Willkommen B 1)
        }
        write(Willkommen B 2)
      }
    write(Willkommen B 3)
    }

    Hoffe das hilft Dir weiter...

  2. Hi,

    function welcome(i)
      {
       if(i == 0)
       {
       }
       else
       {
        document.write("Willkommen A " + i + "<br>");
        i--;
        welcome(i);
        document.write("Willkommen B " + i + "<br>");
       }
      }

    ich versuche es mal, kann aber für nichts garantieren.
    Also bei rekusiven Funktionen werden alle Daten auf einem STack abgelegt und wenn die Abbruchbedingung kommt rückwärts aufgerechnet.
    An Deinem Beispiel:

    i=4 (>0) Also druckt er A4 -> ruft sich selbst mit 3 auf
    i=3 (>0) Also druckt er A3 -> ruft sich selbst mit 2 auf
    i=2 (>0) Also druckt er A2 -> ruft sich selbst mit 1 auf
    i=1 (>0) Also druckt er A1 -> ruft sich selbst mit 0 auf
    i=0 (0=0) also bricht er ab und rechnet rückwärts den unteren Teil der Funktion auf

    d.h i is schon in der if-Anweisung 0 und wird gar nicht noch mal geprüft, da ja dass i--- vor dem Funktionsaufruf kommt

    er sprint also zurück wo i=0 war gibt B0 aus
    und geht wieder eins zurück, dort war i=1 -> B1
    wieder eins zurück ...
    bis B3

    Du musst versuchen DIr vorzustellen, dass mit jedem Funktionsaufruf ein Teller auf einen Stapel gelegt wird, dieser Teller beinhaltet alle Daten, die bis dahin angefallen sind...folgt die Abbruchbedingung, werden alle Teller nacheinander wieder runtergenommen und leergegessen. ;)

    Teller1: i=4 i in der Funktion =3 (da i--)
    Teller2: i=3 i in der Funktion =2(da i--)
    Teller3: i=2 i in der Funktion =1(da i--)
    Teller4: i=1 i in der Funktion =0(da i--)
    Teller5: i=0, Abbruch erfolgt, da Bedingung nicht mehr erfüllt ist, es wird keine neue Funktion mehr aufgerufen

    Teller5: ist also weg, wegen der Abbruchbedingung
    Teller4: i hat intern den Wert 0, ausführen des Restes der Funktion
    Teller3: i hat intern den Wert 1, ausführen des Restes der Funktion
    Teller2 i hat intern den Wert 2 ausführen des Restes der Funktion
    Teller1 i hat intern den Wert 3 ausführen des Restes der Funktion
    letzter Teller weg, Ausgabe

    ich hoffe es war ein wenig verständlich?

    ciao
    romy

  3. Vielen Dank euch beiden für die schnellen und verständlichen Erklärungen.
    Gruß,

    Andreas.