Binary Tree Level Order Traversal

Binary Tree Level Order Traversal

Three types of tree traversals are inorder, preorder, and post order.

A fourth, less often used, traversal is level-order traversal. In a level-order traveresal, all nodes at depth "d" are processed before any node at depth d + 1. Level-order traversal differs from the other traversals in that it is not done recursively; a queue is used, instead of the implied stack of recursion.

My questions on above text snippet are

  1. Why level order traversals are not done recursively?
  2. How queue is used in level order traversal? Request clarification with Pseudo code will be helpful.

Thanks!

9 Answers

Level order traversal is actually a BFS, which is not recursive by nature. It uses Queue instead of Stack to hold the next vertices that should be opened. The reason for it is in this traversal, you want to open the nodes in a FIFO order, instead of a LIFO order, obtained by recursion

as I mentioned, the level order is actually a BFS, and its [BFS] pseudo code [taken from wikipedia] is:

1  procedure BFS(Graph,source):
2      create a queue Q
3      enqueue source onto Q
4      mark source
5      while Q is not empty:
6          dequeue an item from Q into v
7          for each edge e incident on v in Graph:
8              let w be the other end of e
9              if w is not marked:
10                 mark w
11                 enqueue w onto Q

(*) in a tree, marking the vertices is not needed, since you cannot get to the same node in 2 different paths.

void levelorder(Node *n)
{    queue < Node * >q;

     q.push(n);


     while(!q.empty())
     {
             Node *node = q.front();
             cout<<node->value;
             q.pop();
             if(node->left != NULL)
             q.push(node->left);
             if (node->right != NULL)
             q.push(node->right);

     }

}

Instead of a queue, I used a map to solve this. Take a look, if you are interested. As I do a postorder traversal, I maintain the depth at which each node is positioned and use this depth as the key in a map to collect values in the same level

class Solution { public: map<int, vector<int> > levelValues; void recursivePrint(TreeNode *root, int depth){ if(root == NULL) return; if(levelValues.count(root->val) == 0) levelValues.insert(make_pair(depth, vector<int>())); levelValues[depth].push_back(root->val); recursivePrint(root->left, depth+1); recursivePrint(root->right, depth+1); } vector<vector<int> > levelOrder(TreeNode *root) { recursivePrint(root, 1); vector<vector<int> > result; for(map<int,vector<int> >::iterator it = levelValues.begin(); it!= levelValues.end(); ++it){ result.push_back(it->second); } return result; } };

The entire solution can be found here - The solution returns a vector of vectors with each inner vector containing the elements in the tree in the correct order.

you can try solving it here -

And, as you can see, we can also do this recursively in the same time and space complexity as the queue solution!

My questions on above text snippet are

  1. Why level order traversals are not done recursively?
  2. How queue is used in level order traversal? Request clarification with Pseudo code will be helpful.

I think it'd actually be easier to start with the second question. Once you understand the answer to the second question, you'll be better prepared to understand the answer to the first.

How level order traversal works

I think the best way to understand how level order traversal works is to go through the execution step by step, so let's do that.

We have a tree.

We want to traverse it level by level.

So, the order that we'd visit the nodes would be A B C D E F G.

To do this, we use a queue. Remember, queues are first in, first out (FIFO). I like to imagine that the nodes are waiting in line to be processed by an attendant.

Let's start by putting the first node A into the queue.

Ok. Buckle up. The setup is over. We're about to start diving in.

The first step is to take A out of the queue so it can be processed. But wait! Before we do so, let's put A's children, B and C, into the queue also.

Note: A isn't actually in the queue anymore at this point. I grayed it out to try to communicate this. If I removed it completely from the diagram, it'd make it harder to visualize what's happening later on in the story.

Note: A is being processed by the attendant at the desk in the diagram. In real life, processing a node can mean a lot of things. Using it to compute a sum, send an SMS, log to the console, etc, etc. Going off the metaphor in my diagram, you can tell the attendant how you want them to process the node.

Now we move on to the node that is next in line. In this case, B.

We do the same thing that we did with A: 1) add the children to the line, and 2) process the node.

Hey, check it out! It looks like what we're doing here is going to get us that level order traversal that we were looking for! Let's prove this to ourselves by continuing the step through.

Once we finish with B, C is next in line. We place C's children at the back of the line, and then process C.

Now let's see what happens next. D is next in line. D doesn't have any children, so we don't place anything at the back of the line. We just process D.

And then it's the same thing for E, F, and G.

Maya Lin-Takahashi
Author

Maya Lin-Takahashi

Maya is a hardware enthusiast who tests and reviews smart home devices, smartphones, wearables, and audio gear. She focuses on practical consumer value and build quality.