Rekursion und Iteration (2)


Hinter der gezeigten Reduktion einer rechtsrekursiven Problemlösung auf eine iterative Version steht die Idee, den Aktivierungsblock der ersten Inkarnation der Prozedur wiederzuverwenden , statt für die rekursiv aufgerufene Instanz ein neues Exemplar anzulegen. Dies ist möglich, weil sein Inhalt hier nach der Rückkehr aus dem rekursiven Aufruf nicht mehr benötigt wird bis auf die Rückkehr-Information und den Ergebnisverweis, die beide noch richtig stehen; das rekursiv gerufene (bzw. hier direkt aktivierte!) Exemplar benötigt nur neue Eingangsparameterwerte, und die haben wir selbst korrekt umbesetzt.

Wie das Prinzip arbeitet, sehen wir etwa an einem schon früher angesprochenen Beispiel: Kopieren einer linear verketteten Liste. An der unmittelbar naheliegenden rekursive Version

PROCEDURE copy(l: liste; VAR p: liste):
BEGIN IF l <> NIL 
      THEN NEW(p); 
           p^.wert := l^.wert; copy(l^.tail, p^.tail);
      ELSE p := NIL;
      END;
END copy;
stört uns, daß sich der Ergebnisparameter p beim rekursiven Aufruf auf ein anderes Objekt als beim Erstaufruf bezieht. Wir verwenden für das Kopieren des Listenschwanzes nun eine neue Routine copytail,  der wir den Bezug  auf den bereits existierenden  Kopf der neuen Liste als Wertparameter  mitgeben, und die nur den Schwanz der Liste kopieren soll:
PROCEDURE copy(l: liste; VAR p: liste):
BEGIN IF l <> NIL 
      THEN NEW(p); 
           p^.wert := l^.wert; copytail(l, p);
      ELSE p := NIL;
      END;
END copy;
Die Routine copytail  wird nun nicht mehr mit einer leeren Liste aufgerufen; der Sonderfall ist nun, daß die Liste nur aus dem Kopf besteht.


zurück | Inhalt | Index | vor | Vorlesung

Klaus Lagally, 22. Februar 2000, 19:36