Topics
General Approach to replace tail recursion with a loop:
- Identify the parameters that get updated at each recursive call.
- Initialize those parameters before the loop using the initial arguments.
- Convert the recursion condition (base case) to a loop condition.
- Update the parameters at the end of the loop body to mirror what happens in the tail-recursive call.
- Return the result once the termination condition is reached.
Classic example of computing factorial of a number n
:
ll factorial_tail_recursive(ll n, ll accumulator) {
if (n <= 1) {
return accumulator;
}
return factorial_tail_recursive(n - 1, n * accumulator);
}
ll factorial_iterative(ll n) {
ll res = 1;
while (n > 1) {
res *= n;
n--;
}
return res;
}
Another interesting example is computing fibonacci number:
def fib_naive(n):
if n < 2:
return n
return fib_naive(n - 1) + fib_naive(n - 2)
def fib_tail(n, a=0, b=1):
if n == 0:
return a
if n == 1:
return b
return fib_tail(n - 1, b, a + b)
def fib_iter(n):
if n == 0:
return 0
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
Note how we converted fib_naive
(non-tail recursive) to fib_tail
: a tail-optimized version by keeping track of the last two computed values. After that it’s straightforward to create the iterative version.