What is the differences between Recursive VS Nonrecursive for binary tree traversal?
Which one is best for a large tree and Why?
Thanks
Recursive functions are simpler to implement since you only have to care about a node, they use the stack to store the state for each call.
Non-recursive functions have a lot less stack usage but require you to store a list of all nodes for each level and can be far more complex than recursive functions.
The difference is that a recursive way uses the call stack whereas an iterative way uses an explicit stack (the stack data structure). What this leads to are two things:
1) If it is a large tree, a recursive way can cause stack overflow.
2) With an iterative approach, you can stop somewhere in the middle of the traversal. In other words, you can implement something like a pre-order/in-order/post-order iterator with a stack. This can be useful in some cases.
Related
This query has been in my mind for many days and I wanted someone to clear it.
Problem:- Find the number of nodes in a binary tree
Approach 1 :- (Iterative)
Do Inorder traversal using the stack. whenever you are popping elements from the stack, keep a count of it which are number of nodes in a binary tree.
Time Complexity - O(n)
Space Complexity - O(n)
Approach 2 :- (Recursive)
Time Complexity - O(n)
Space Complexity - O(1) or O(n)????
We can do inorder traversal recursively, but in an interview, which approach would be optimal expressing to the interviewer.....Iterative or recursive?? and also should i consider the recursive call stack space which boils down the space complexity to O(n) or should i stick with the O(1) Space complexity?
Your question - "which approach would be optimal expressing to the interviewer" - can't really be answered by anyone except the interviewer themself. However, the differences between the possible approaches to this problem are worthy of discussion.
For a start, let's note that both the iterative and recursive approaches use a stack; the iterative approach has an explicit stack, but a recursive function works using a call stack which is not managed by the programmer. Therefore the auxiliary space used by either approach will be asymptotically the same, but with a lower constant for the iterative approach since it only pushes nodes to the stack, while the recursive approach pushes whole call frames, including all local variables.
Note that the auxiliary space is O(h) where h is the height of the tree, not O(n) where n is the number of nodes. This is important because the worst case will depend on whether or not the tree is balanced. For an unbalanced tree, the height h is O(n) in the worst case, whereas for a balanced tree, h is O(log n). The question doesn't specify that the tree is balanced, so there is a risk that the recursive approach will overflow the stack when the height of the tree is too large. In contrast, the iterative approach stores an explicit stack in main memory.
That's all a discussion of efficiency, but there is more to programming than algorithmic efficiency. For instance, if the tree is never going to be very large, you might prefer the recursive approach since it is much simpler to write; it takes only a few lines of very clean code. The imperative approach needs to create a stack, and push and pop from it in a loop, so the code is likely to be longer and harder to understand. Don't underestimate the value of clean, easy-to-understand code.
The other thing is that you have jumped straight to in-order traversal as the solution to the problem, but if the problem is to count the number of nodes in a binary tree, then you can traverse it in any order. Pre-order traversal is a bit simpler to implement iteratively than in-order traversal, and is just as efficient.
Alternatively, if the data structure itself can be modified, then it is straightforward to give each node a property holding the cardinality of its subtree. The insert, delete and rebalance operations will need to be modified to maintain this property, but the extra work is O(1), and it allows the size of the tree to be computed in O(1) by simply reading the root node's cardinality property. Adding this property has other benefits, such as supporting a "find the kth node" operation in O(h) time instead of O(h + k).
well I am currently learning data structure and algorithm. I got two methods of traversal in binary search tree.
(1)-stack implementation
(2)-recursive call method
which one performance wise is better?
As long as the algorithm remain same, performance should also be same. In your case: performance remains same because in both cases, stacks are used.
In, stack implementation programmer explicitly maintaining a stack for traversal. And in recursive call method, programs internal call stack is used for traversal.
EDIT:
and what about running time complexity ??
Running time complexity would be same for both of the cases. But execution time could be different depending on the implementation. As there is no code/implementation provided, "in general sense, recursion could take much longer time because
recursion (implemented naively) involves pushing a stack frame,
jumping, returning, and popping back from the stack.
For more information you can check the following links:
Is recursion faster than loops
Looping versus recursion for improved application performance
Why should one choose recursion over iteration, when a solution has the same time complexity for both cases but better space complexity for iterative?
Here's a particular example of a case where there are extra considerations. Tree search algorithms can be defined recursively (because each subtree of a tree is a tree) or iteratively (with a stack). However, while a recursive search can work perfectly for finding the first leaf with a certain property or searching over all leaves, it does not lend itself to producing a well-behaved iterator: an object or function state that returns a leaf, and later when called again returns the next leaf, etc. In an iterative design the search stack can be stored as a static member of the object or function, but in a recursive design the call stack is lost whenever the function returns and is difficult or expensive to recreate.
Iteration is more difficult to understand in some algorithms. An algorithm that can naturally be expressed recursively may not be as easy to understand if expressed iteratively. It can also be difficult to convert a recursive algorithm into an iterative algorithm, and verifying that the algorithms are equivalent can also be difficult.
Recursion allows you to allocate additional automatic objects at each function call. The iterative alternative is to repeatedly dynamically allocate or resize memory blocks. On many platforms automatic allocation is much faster, to the point that its speed bonus outweighs the speed penalty and storage cost of recursive calls. (But some platforms don't support allocation of large amounts of automatic data, as mentioned above; it's a trade-off.)
recursion is very beneficial when the iterative solutions requires that you simulate recursion with a stack. Recursion acknowledges that the compiler already manages a stack to accomplish precisely what you need. When you start managing your own, not only are you likely re-introducing the function call overhead you intended to avoid; but you're re-inventing a wheel (with plenty of room for bugs) that already exists in a pretty bug-free form.
Some Benefits for Recursion
Code is Perfect Elegant (compared to loops)
very useful in backtracking data structures like LinkedList, Binary Search Trees as the recursion works by calling itself in addition stack made especially for this recursive calls and each call chained by its previous one
I am more comfortable with implementing recursive methods over iterative ones. While studying for the exam, i implemented a recursive BFS(Breadth-First Search) using Queues, but while searching online for a recursive BFS that uses Queues, i kept on reading that BFS is an iterative algorithm not a recursive one. So is there any reason to choose one over the other?
Iterative is more efficient for the computer. Recursive is more efficient for the programmer and more elegant (perhaps).
The problem with recursive is each recursive call pushes the state/frame onto the call stack, which can quickly lead to resource exhaustion (stack overflow!) for deep recursion. But, the solutions are often easier to code and read.
Iterative performs better because it's all done in the local frame. However, converting recursive to iterative can reduce readabiity due to the introduction of variables to cater for the progression of the algorithm.
Chose whatever implementation is easiest to code and maintain. Only worry if you have a demonstrated problem.
Iterative and recursive both have same time complexity.difference is: recursive programs need more memory as each recursive call pushes state of the program into stack and stackoverflow may occur.but recursive code is easy to write and manage.You can reduce the space complexity of recursive program by using tail recursion.
Iterative implementations are usually faster. One example is fibonacci series. It's faster to implement it in a simple loop over a recursive solution.
More discussion here Recursion or Iteration?
I am reading through this article, where it is mentioned that we can get rid of one side of the tree by performing rotations in a specific manner, and then traversing the tree down in one direction and deleting the elements.
Although I understand what they are trying to do, I do not understand why?
What advantages might this type of deletion provide as opposed to a simple postorder deletion?
One advantage I can think of is saving on the memory used by recursion, but I think that is an insignificant overhead as compared to traversing the tree twice, once for rotating, and then for deleting. Am I missing something here?
The article seems to be staying that the point of this method is to avoid recursion (and its consumption of stack space): "Hmm...what if we rearranged nodes so that they didn't have any left subtrees? Then we could just descend to the right, without need to keep track of anything on a stack."
In general, I prefer to avoid recursion when I cannot be sure that its depth will be reasonable, because you will run out of stack space long before you run out of any other sort of memory - in some cases because the system is designed to limit recursion to catch errors causing infinite recursion. However, I think this is less important here, where you have already admitted that other routines in the same package need recursion. Also, the depth of recursion depends on the depth of the tree, and for a balanced tree this will be roughly the logarithm of the number of nodes it it, and so should never be too deep.