2

How to keep track of the level while traversing a binary tree in level order or breadth-first order?

The nodes in the binary tree have left and right references only.

I want to be able to distinguish between each row of nodes.

Here is my method for level-order traversal:

private static Queue<Node> traverseLevelOrder(final Node node)
{
    final Queue<Node> temporaryQueue = new LinkedList<Node>(); // Temporary queue is used for traversal.
    final Queue<Node> permanentQueue = new LinkedList<Node>(); // Permanent queue is used for node storage.

    // Add the root node, as current, to the queue.
    Node current = node;
    temporaryQueue.add(current);
    permanentQueue.add(current);

    while (!temporaryQueue.isEmpty())
    {
        current = temporaryQueue.remove();
        System.out.println(String.valueOf(current));

        // Check current's children.
        if (current != null)
        {
            final Node left = current.getLeft();
            final Node right = current.getRight();

            current = left;
            if (current != null)
            {
                temporaryQueue.add(current);
                permanentQueue.add(current);
            }

            current = right;
            if (current != null)
            {
                temporaryQueue.add(current);
                permanentQueue.add(current);
            }
        }
    }

    return permanentQueue;
}
XP1
  • 6,910
  • 8
  • 54
  • 61

4 Answers4

3
public void bfs(Node root) {
    Queue<Node> q = new LinkedList<Node>();
    Node dummy = new Node(null);

    q.add(root);
    q.add(dummy);

    while(!q.isEmpty()) {
        Node curr = q.poll();

        if(curr != null) {
            System.out.print(curr.data + " ");

            if(curr.left != null)
                q.insert(curr.left);
            if(curr.right !== null)
                q.insert(curr.right);
        } else {
            System.out.println();
            if(!q.isEmpty())
                q.insert(dummy);
        }
    }
}

This code does not show the in-between null nodes.

Bhushan
  • 18,329
  • 31
  • 104
  • 137
  • 1
    For a complete binary tree having depth 3 [ 8 nodes ] your logic would give [ A DUMMY B C DUMMY D E DUMMY F G DUMMY ] when [ A DUMMY B C DUMMY D E F G DUMMY ] is being expected. – Pavan Dittakavi Aug 19 '12 at 20:49
2

It is possible to keep track of the level when you know that the number of nodes doubles each level. For example, in level 0, there is only 1 node; in level 1, there are 2 nodes; in level 2, there are 4 nodes; in level 3, there are 8 nodes; in level 4, there are 16 nodes; etc.

The code for grouping each level of nodes into an array using level-order traversal in Java may look like this:

private static Node[][] toArrayLevels(final Node node)
{
    final Queue<Node> temporaryQueue = new LinkedList<Node>(); // Temporary queue is used for level-order traversal.

    final ArrayList<Node[]> tree = new ArrayList<Node[]>(); // Levels containing their nodes.
    ArrayList<Node> nodes = new ArrayList<Node>(); // Current level containing its nodes.

    Node[][] treeArray = new Node[][]{};
    Node[] nodesArray = new Node[]{};

    Node current = node; // Level 0.
    int level = 1; // Node's children are level 1.
    temporaryQueue.add(current);

    nodes.add(current);
    tree.add(nodes.toArray(nodesArray));

    nodes = new ArrayList<Node>(2);

    while (!temporaryQueue.isEmpty())
    {
        // When the nodes completely fill the maximum spaces (2 ^ level) allowed on the current level, start the next level.
        if (nodes.size() >= Math.pow(2, level))
        {
            tree.add(nodes.toArray(nodesArray));
            nodes = new ArrayList<Node>((int) Math.pow(2, level));
            level += 1;
        }

        current = temporaryQueue.remove();

        // Check current's children.
        if (current != null)
        {
            final Node left = current.getLeft();
            final Node right = current.getRight();

            temporaryQueue.add(left);
            nodes.add(left);

            temporaryQueue.add(right);
            nodes.add(right);
        }
        else
        {
            // Null nodes fill spaces used to maintain the structural alignment of the tree.
            nodes.add(null);
            nodes.add(null);
        }
    }

    // Push remaining nodes.
    if (nodes.size() > 0)
    {
        tree.add(nodes.toArray(nodesArray));
    }

    return (tree.toArray(treeArray));
}

It checks the number of nodes on the current level. When the nodes have filled the current level, then it starts a new level.

As an example, a binary tree may look like this:

Level 0:                                60
                         /                              \
Level 1:                50                              65
                 /              \                /              \
Level 2:        49              55              --              66
             /      \        /      \        /      \        /      \
Level 3:    --      --      --      --      --      --      --      71

Here is the output of the example:

System.out.println(Arrays.deepToString(binaryTree.toArrayLevels()));

[[{60}], [{50}, {65}], [{49}, {55}, null, {66}], [null, null, null, null, null, null, null, {71}], [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]]

[
    [{60}], // Level 0.
    [{50}, {65}], // Level 1.
    [{49}, {55}, null, {66}], // Level 2.
    [null, null, null, null, null, null, null, {71}], // Level 3.
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null] // Level 4.
]

Here is the JavaScript version:

function toArrayLevels(node)
{
    var temporary = []; // Temporary is used for level-order traversal.

    var tree = []; // Levels containing their nodes.
    var nodes = []; // Current level containing its nodes.

    var current = node; // Level 0.
    var level = 1; // Node's children are level 1.

    temporary.push(current);
    tree.push([current]);

    while (temporary.length > 0)
    {
        // When the nodes completely fill the maximum spaces (2 ^ level) allowed on the current level, start the next level.
        if (nodes.length >= Math.pow(2, level))
        {
            tree.push(nodes);
            nodes = [];
            level += 1;
        }

        current = temporary.shift();

        // Check current's children.
        if (current !== null)
        {
            var left = current.left;
            var right = current.right;

            temporary.push(left);
            nodes.push(left);

            temporary.push(right);
            nodes.push(right);
        }
        else
        {
            // Null nodes fill spaces used to maintain the structural alignment of the tree.
            nodes.push(null);
            nodes.push(null);
        }
    }

    // Push remaining nodes.
    if (nodes.length > 0)
    {
        tree.push(nodes);
    }

    return tree;
}
XP1
  • 6,910
  • 8
  • 54
  • 61
1

Here's a code I wrote to find the left view of a binary tree without recursion. Here I am keeping track of the number of nodes considering a null as a node in the tree istself. The number of null nodes for a null node in a paricular level will double up in the next level. The currNulls and nextNulls are keeping track of the nulls at the current and next level

void leftView(Node root){
        if(root==null) return;
        boolean newL=true;
        int level=0,count=0,nextNulls=0,currNulls=0;
        Queue<Node> q=new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
           Node node=q.remove();
           if(newL){
               System.out.print(node.data+" ");
               newL=false;
           }
           count++;
           if(node.left!=null){
               q.add(node.left);
           }
           else{
               nextNulls++;
           }
           if(node.right!=null){
               q.add(node.right);
           }
           else{
               nextNulls++;
           }
           if(1<<level == count+currNulls){
               level++;
               newL=true;
               count=0;

            //   System.out.println("Curr -"+currNulls+"\tNext - "+nextNulls);

               currNulls=nextNulls;
               nextNulls=2*nextNulls;
           }
        }
    }
0

here's my javascript version of the level order traversal, which should point you in the right direction

I watched this video before writing this

var discovered = [];

var getLevels = function(node) {
    if (node == null) { return []}
    discovered.push(node)
    var levels = levelOrderTraverse(discovered,[])
    return levels
}

function levelOrderTraverse(discovered,elms) {
    var level = []
    for (var i = 0; i < discovered.length; i++) {
        level.push(discovered[i].val)
    }
    elms.push(level);
    var newlyDiscovered = [];
    for (var i = 0; i < discovered.length; i++) {
        if (discovered[i].left != null) {
            newlyDiscovered.push(discovered[i].left)
        }
        if (discovered[i].right != null) {
            newlyDiscovered.push(discovered[i].right)
        }
    }
    if (newlyDiscovered.length > 0) {
        levelOrderTraverse(newlyDiscovered,elms)
    }
    return elms
}

also can be found on my github with tests

Daniel McGrath
  • 454
  • 5
  • 6
  • May you please explain your code instead of just answering with code? – Baaing Cow Oct 19 '18 at 20:46
  • sure - it's exactly like its described in the video. the discovered nodes are the children nodes of each node already in the discovered nodes array. so you start with the root, discover its children, iterate over these children (2 of them for left and right) and find their children (at most 4 of them because each of the previous 2 can have a left and right), etc. and you can see how the number of discovered nodes varies and gives the levels. each level you discover gets pushed into the multidimensional discovered array, and then you can iterate over this array of dynamic arrays – Daniel McGrath Oct 19 '18 at 20:56