Tail Recursion
Tail recursion is a type of recursive function where the last statement executed within the function is a recursive call. Nothing remains to be executed after the recursive call.
A tail recursive function is one in which the recursive call occurs as the final operation before returning from the function.
It doesn't require tracking intermediate values during the recursive calls.
Comparison of Tail Recursion versus Non-Tail Recursion
Below, I make a comparison between tail-recursive and non-tail-recursive functions using examples.
Non-tail-recursive factorial
def factorial_non_tail(n):
if n <= 0:
return 1
return n * factorial_non_tail(n - 1)
Tail-recursive factorial
def factorial_tail(n, acc=1):
if n <= 1:
return acc
return factorial_tail(n - 1, n * acc)
print("factorial_non_tail", factorial_non_tail(5)) # Output: 120
print("factorial_tail", factorial_tail(5)) # Output: 120
In the tail-recursive version, we accumulate the factorial value in the acc argument, avoiding unnecessary stack frames.
Time & Space Complexity
Both implementations have a time complexity of O(n) (where n is the input).
The non-tail-recursive version has an auxiliary space complexity of O(n), while the tail-recursive version uses only O(1) auxiliary space.
Advantages of Tail-Recursive Functions
- It is more efficient because it can be optimized by the compiler
- Non-tail recursive functions use more stack space due to the need to maintain information for each recursive call. However, tail recursion doesn't accumulate stack frames unnecessarily.
Remember, tail recursion is a powerful concept that allows for more efficient recursive functions, especially when dealing with large inputs!