Strictly speaking, recursion and iteration are both equally powerful. Any recursive solution can be implemented as an iterative solution with a stack. The inverse transformation can be trickier, but most trivial is just passing the state down through the call chain.
In Java, there is one situation where a recursive solution is better than a (naive) iterative one, and one situation where they are basically equivalent. In most other cases, the iterative solution will be superior, since function call overhead is avoided.
If the function uses a stack implicitly, then the recursive solution will typically be superior. Consider a depth-first search:
void walkTree(TreeNode t) {
doSomething(t);
if (t.hasLeft()) { walkTree(t.getLeft()); }
if (t.hasRight()) { walkTree(t.getRight()); }
}
compared to the equivalent iterative solution
void walkTree(TreeNode t) {
Stack<TreeNode> s = new Stack<TreeNode>();
s.push(t);
while (!s.empty()) {
TreeNode t = s.pop();
doSomething(t);
if (t.hasLeft()) { s.push(t.getLeft()); }
if (t.hasRight()) { s.push(t.getRight()); }
}
}
In the iterative case, you will have to pay for any garbage created by the Stack<>
object. In the recursive case, you will use the process stack, which will not create any garbage or allocate any memory. The recursive solution is vulnerable to a stack overflow, but will run faster otherwise.
If the function uses tail recursion, then the two solutions will be equivalent because the JIT will transform the recursive one into the iterative one. Tail recursion is when the last thing that a function does is invoke itself recursively, allowing the compiler to ignore any accumulated state. For example, traversing a list
void walkList(ListNode n) {
doSomething(n);
if (n.hasNext()) { walkList(n.getNext()); }
}
Since "walkList" is the last thing done in the function, the JIT will transform it essentially into a "n = n.getNext(); goto beginning", which wil make it equivalent to the iterative solution.
In most other situations, an iterative solution will be superior. For example, if you wanted to do a breadth-first search, then you could use a Queue
instead of a Stack
in the iterative solution, and have it work instantly, while transforming it to a recursive solution requires that you pay for both the implicit stack in the call stack, and still pay for the queue.