Ja, einige Sprachen und Compliler konvertieren rekursive Logik in nicht rekursive Logik. Dies wird als Tail-Call-Optimierung bezeichnet. Beachten Sie, dass nicht alle rekursiven Aufrufe für die Tail-Call-Optimierung geeignet sind. In dieser Situation erkennt der Compiler eine Funktion der Form:
int foo(n) {
...
return bar(n);
}
Hier kann die Sprache erkennen, dass das zurückgegebene Ergebnis das Ergebnis einer anderen Funktion ist, und einen Funktionsaufruf mit einem neuen Stapelrahmen in einen Sprung umwandeln.
Beachten Sie, dass die klassische Fakultätsmethode:
int factorial(n) {
if(n == 0) return 1;
if(n == 1) return 1;
return n * factorial(n - 1);
}
ist wegen der bei der rückgabe notwendigen inspektion nicht schwanzrufoptimierbar.
Um diesen Tail Call zu optimieren,
int _fact(int n, int acc) {
if(n == 1) return acc;
return _fact(n - 1, acc * n);
}
int factorial(int n) {
if(n == 0) return 1;
return _fact(n, 1);
}
Kompilieren Sie diesen Code mit gcc -O2 -S fact.c
(-O2 ist erforderlich, um die Optimierung im Compiler zu ermöglichen, aber mit mehr Optimierungen von -O3 wird es für einen Menschen schwer zu lesen ...)
_fact:
.LFB0:
.cfi_startproc
cmpl $1, %edi
movl %esi, %eax
je .L2
.p2align 4,,10
.p2align 3
.L4:
imull %edi, %eax
subl $1, %edi
cmpl $1, %edi
jne .L4
.L2:
rep
ret
.cfi_endproc
Man kann in dem Segment sehen .L4
, die jne
eher als ein call
(das macht einen Subroutinen - Aufruf mit einem neuen Stapelrahmen).
Beachten Sie, dass dies mit C durchgeführt wurde. Die Optimierung von Tail-Aufrufen in Java ist schwierig und hängt von der JVM-Implementierung ab. Tail-Recursion + Java und Tail-Recursion + Optimierung sind gute Tag-Sets zum Durchsuchen. Sie können andere JVM Sprachen sind in der Lage zu optimieren Endrekursion finden besser (try clojure (die die erfordert recur zu Endrekursion optimize) oder scala).
return recursecall(args);
für die Rekursion, desto komplexer Sachen durch die Schaffung eines expliziten Stapel möglich ist und es auf kurvigen, aber ich bezweifle , werden sie