14

Recursive mechanism to find max depth of depth of binary tree is very straightforward, but how can we do it efficiently without recursion as I have large tree where I would rather avoid this recursion.

//Recursive mechanism which I want to replace with non-recursive
private static int maxDepth(Node node) {
if (node == null) return 0;
    return 1 + Math.max(maxDepth(node.left), maxDepth(node.right)); 
}

PS: I am looking for answers in Java.

Hemant
  • 4,537
  • 8
  • 41
  • 43

7 Answers7

15

This variant uses two stacks, one for additional nodes to explore (wq) and one always containing the current path from the root (path). When we see the same node on the top of both stacks it means we've explored everything below it and can pop it. This is the time to update the tree depth too. On random or balanced trees the additional space should be O(log n), in the worst case O(n), of course.

static int maxDepth (Node r) {
    int depth = 0;
    Stack<Node> wq = new Stack<>();
    Stack<Node> path = new Stack<>();

    wq.push (r);
    while (!wq.empty()) {
        r = wq.peek();
        if (!path.empty() && r == path.peek()) {
            if (path.size() > depth)
                depth = path.size();
            path.pop();
            wq.pop();
        } else {
            path.push(r);
            if (r.right != null)
                wq.push(r.right);
            if (r.left != null)
                wq.push(r.left);
        }
    }

    return depth;
}

(Shameless plug: I had this idea for using dual stacks for non-recursive traversals a few weeks ago, check for a C++ code here http://momchil-velikov.blogspot.com/2013/10/non-recursive-tree-traversal.html not that I claim I was the first to invent it :)

chill
  • 16,470
  • 2
  • 40
  • 44
  • Thanks - I have accepted your answer, as it is not keeping list of nodes traveled which added space complexity. – Hemant Nov 11 '13 at 21:13
  • An implementation note: it's better to use `ArrayDeque` instead of `Stack` in Java: the `Stack` class is unnecessarily synchronized. – Tagir Valeev Dec 27 '15 at 05:05
2

The recursive approach you've described is essentially a DFS over the binary tree. You can implement this iteratively if you'd like by storing an explicit stack of nodes and keeping track of the maximum depth encountered.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • Can you provide any sample? Is this efficient way? As I don't want to increase space complexity. – Hemant Nov 10 '13 at 05:24
  • @Hemant- Iterative and recursive DFS's have the same time and space complexities, though the recursive version typically uses stack space while the iterative version uses heap space. Search for "iterative DFS" for some good pseudocode to use as a starting point. – templatetypedef Nov 10 '13 at 05:38
2

I have written following logic to do find max and min depth which doesn't involve recursion and without increasing the space complexity.

// Find the maximum depth in the tree without using recursion
private static int maxDepthNoRecursion(TreeNode root) {
    return Math.max(maxDepthNoRecursion(root, true), maxDepthNoRecursion(root, false)); 
}

// Find the minimum depth in the tree without using recursion
private static int minDepthNoRecursion(TreeNode root) {
    return Math.min(maxDepthNoRecursion(root, true), maxDepthNoRecursion(root, false)); 
}

private static int maxDepthNoRecursion(TreeNode root, boolean left) {
    Stack<TreeNode> stack = new Stack<>();
    stack.add(root);
    int depth = 0;
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        if (left && node.left != null) stack.add(node.left);
        // Add the right node only if the left node is empty to find max depth
        if (left && node.left == null && node.right != null) stack.add(node.right); 
        if (!left && node.right != null) stack.add(node.right);
        // Add the left node only if the right node is empty to find max depth
        if (!left && node.right == null && node.left != null) stack.add(node.left);
        depth++;
    }
    return depth;
}
Hemant
  • 4,537
  • 8
  • 41
  • 43
  • 1
    You don't really need to keep track of visited nodes, because in a tree there's a single path from the root to any other node. – chill Nov 10 '13 at 10:17
  • @chill - Not keeping track of visited nodes causes recursion, even though tree doesn't have any circular reference. – Hemant Nov 11 '13 at 17:35
  • oh, you mean with your particular algorithm? OK. See my answer for a variant with expected O(log n) additional space complexity. – chill Nov 11 '13 at 19:36
  • 1
    The algorithm does not appear to work for certain formations of the tree. It is returning max depth of 3 for the below tree (expected 4). node1.left=node2; node1.right=node3; node2.left=node4; node2.right=node5; node3.left=node6; node3.right=node7; node5.right=node8; node6.left=node9; – user321532 Nov 03 '14 at 06:01
  • totally wrong algorithm it will be considered only if the max depth on the left of the left node of the roor or on the right of the right node of the root of the tree . try this and it will fail tree2.Insert(30); tree2.Insert(10); tree2.Insert(50); tree2.Insert(5); tree2.Insert(11); tree2.Insert(12); tree2.Insert(13); tree2.Insert(14); – John Donvan Jan 28 '17 at 21:00
1

Another way is to use Level order traversal, where tree height is equal to the number of level of a tree. (It can only be use to calulate the minimal height of a tree.)

public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    LinkedList<TreeNode> arr = new LinkedList<TreeNode>(); // queue for current level
    LinkedList<TreeNode> tmp = new LinkedList<TreeNode>(); // queue for next level
    arr.add(root);
    int res = 0; // result
    TreeNode node; // tmp node 
    while (true) {
        while (!arr.isEmpty()) {
            node = arr.poll();
            if (node.left != null) tmp.add(node.left);
            if (node.right != null) tmp.add(node.right);
        }
        res++;
        if (tmp.isEmpty()) break;
        arr = tmp;
        tmp = new LinkedList<TreeNode>();
    }
    return res;
}
vancexu
  • 1,548
  • 3
  • 19
  • 30
0

If you can maintain left and right values at each node, it can be done.

http://leetcode.com/2010/04/maximum-height-of-binary-tree.html.

Possible duplicate: Retrieving a Binary-Tree node's depth non-recursively

Community
  • 1
  • 1
Prasad K - Google
  • 2,584
  • 1
  • 16
  • 18
0

Using a Array to store a layer of nodes, each time find a new layer. the depth plus one.

public int maxDepth2(TreeNode root){
        if(root == null){
            return 0;
        }

        int depth = 0;

        ArrayList<TreeNode> oneLayer = new ArrayList<TreeNode>();
        oneLayer.add(root);

        while(!oneLayer.isEmpty()){
            ArrayList<TreeNode> newLayer = new ArrayList<TreeNode>();
            for(TreeNode node:oneLayer){
                if(node.right!=null){
                    newLayer.add(node.right);
                }
                if(node.left!=null){
                    newLayer.add(node.left);
                }
            }
            oneLayer = newLayer;
            depth++;
        }

        return depth;
    }
Jerry Z.
  • 2,031
  • 3
  • 22
  • 28
0

Here is a BFS solution:

private class NodeHeight
{
    public Node node;
    public int height;

    public NodeHeight(Node n, int height)
    {
        node = n;
        this.height = height;
    }
}

public int GetHeightBfs(Node root)
{
    if(root == null)
        return 0;
    else
        return GetHeightBfs(new NodeHeight(root, 1))
}

private int GetHeightBfs(NodeHeight root)
{   
    int maxHeight = int.Min;
    int minHeight = int.Max;
    var q = new Queue<Node>();
    q.Enqueue(root);
    while(q.length > 0)
    {       
        var nodeHeight = q.Dequeue();
        var node = nodeHeight.node;
        int height = nodeHeight.height;
        if(node.left == null && node.right == null)
        {
            maxHeight = Math.max(maxHeight, height);
            minHeight = Math.min(minHeight, height);
        }

        if(node.left != null)
            q.Enqueue(new NodeHeight(node.left, height + 1);

        if(node.right != null)
            q.Enqueue(new NodeHeight(node.right, height + 1);
    }

    return maxHeight;
}   

Note that you can also return minHeight. To make it DFS just replace Queue with Stack.