How to construct a binary tree from just the level order traversal string

5.1k views Asked by At

Consider a binary tree with the following properties:

  1. An internal node (non-leaf node) has a value 1 if it has two children.
  2. A leaf node has a value 0 since it has no children.

A level order traversal on the tree would generate a string of 1s and 0s (by printing the weird value at each node as they are visited). Now given this string construct the binary tree and perform a post order traversal on the tree. The post order string should be the output of the program.

For example: Input String is 111001000. Create a binary tree from this. Then perform the post order traversal on the tree which would result in an output: 001001011

The "crux" of the problem is to create the binary tree from just the level order string. How would I do this?

6

There are 6 answers

0
Jinson George On BEST ANSWER

Conceptually more simpler I think.

import java.util.LinkedList;
import java.util.Queue;

class WeirdBinaryTree
{
static class Node
{
    private Node right;
    private Node left;
    private int weirdValue;

    public void setWeirdValue(int value)
    {
        weirdValue=value;
    }
}

private static Node makeTree(String str)throws Exception
{
    char[] array=str.toCharArray();
    Node root=new Node();
    Queue<Node> list=new LinkedList();
    list.add(root);
    int i=0;
    Queue<Node> nextList=new LinkedList<Node>();
    while(!list.isEmpty())
    {
        if(array[i++]=='1')
        {                
                Node temp=list.poll();
                temp.left=new Node();
                temp.right=new Node();
                temp.setWeirdValue(1);
                nextList.add(temp.left);
                nextList.add(temp.right);       
        }
        else
        {
            list.poll();
        }
        if(list.isEmpty())
        {
            list=nextList;
            nextList=new LinkedList<Node>();
        }
    }
    return root;
}

private static void postTraversal(Node localRoot)
{
    if(localRoot!=null)
    {
        postTraversal(localRoot.left);
        postTraversal(localRoot.right);
        System.out.print(localRoot.weirdValue);
    }
}

public static void main(String[] args)throws Exception 
{
    postTraversal(makeTree("111001000"));
}
}
0
Danstahr On

First, I assume that your level order traversal is basically a BFS.

Now, let's have a look at the string. Performing the BFS, we print "1" if the current node's got two sons. Otherwise, it's a leaf and we print 0, terminating the processing of the current branch.

Consequently, during the reverse task, we can remember the list of open branches' last nodes and append the incoming nodes there.

Let's demonstrate this approach on an example:

Level 1:

Tree :   
        1 - id 0
Open branches : 0 0 (left and right son)
Remaining string : 11001000

*********

Level 2:

Tree :   
        1
      1    1 
Open branches : 1 1 2 2
Remaining string : 001000

*********

Level 3:

Tree : 
       1
    1     1
   0  0  1  0

Open branches : 5 5

Remaining string : 00


Level 4:

Tree : 
       1
    1     1
   0  0  1  0
        0 0

 No more input, we're done.

Having the tree, the post-order traversal is trivial.

And the code (it assumes that the tree is quite dense, otherwise it's not very memory efficient):

import java.util.ArrayDeque;
import java.util.Queue;

public class Main {
static final int MAX_CONST = 50;

public static void main(String[] args) {
    String evilString = "111001000"; // Assuming this string is a correct input

    char[] treeRepr = new char[MAX_CONST];
    Queue<Integer> q = new ArrayDeque<Integer>();
    q.add(0);       
    for (int i = 0; i < evilString.length(); ++i) {
        int index = q.remove();
        char ch = evilString.charAt(i);
        if (ch == '1') {
            q.add(2*(index+1)-1);
            q.add(2*(index+1));
        }
        treeRepr[index] = ch;
        // System.out.println(q.size());
    }   
    System.out.println(arrToString(treeRepr, 0, new StringBuilder()));
}

public static StringBuilder arrToString(char[] array, int index, StringBuilder sb) {
    if (array[index] == '1')
    {
        arrToString(array, 2*(index+1)-1, sb);
        arrToString(array, 2*(index+1), sb);
    }
    sb.append(array[index]);
    return sb;
}
}
0
3yakuya On

If it was allowed, I would use a binary heap as a helper here. In a binary heap implemented using a standard table, given an index of an element we can easily calculate its parent's index: int parent = (index-1)/2;. Knowing this, we would need to start at the beginning of our table and do the folowing:

  1. Set the binaryHeap[0] to the first number from the input stream;
  2. for all the remaining elements in input stream:

      do{
         binaryHeap[heapIndex] = -1;
         if (parent(heapIndex) = 1)
               binaryHeap[heapIndex] = nextElementFromTheInputStream;
         heapIndex++;
      }
      while(binaryHeap[heapIndex - 1] == 0);
    

So basically, we move through our table. We initialize each field (except root at 0) to be -1, which means there is no node there. Then we check if the parent of that field was 1. If it was, then we place next element from the input stream on our current index in the heap (heapIndex). If the parent of a current field is 0, we just go further, because that means our parent is a leaf and is not supposed to have any children.

Then we can run post-order algorithm on the heap (probably it would be worth implementing some security-code, so that no element with "-1" is placed in the output stream. Just interpret leftChild(heapIndex) == -1; or rightChild(heapIndex) == -1; to be NULL).

This algorithm is probably quite inefficient in terms of memory, but I hope it is quite easy to understand.

1
Vishal R On

Taking your example of level order traversal - 111001000 The tree would be as follows

      A
    /   \ 
   B     C
  /\     /\
 D  E   F  G
       /\
      H  I

The logic is as follows.

1) Take first bit if its 1 (root) - then next 2^1 are values of children of that parent. So 2nd and 3rd bits are childern of A (root).

2) Go to next bit (1 for B) as its value is also 1 it also has 2 children and then next bit (1 for C) which also has 2 children. Second level is over and as we have 2 1's so 2^2 next bits are for level 3.

3) 111 001000 so this we have traversed and next 4 bits are children on 3rd level. 4th and 5th bits being 0 (D and E are leaf nodes and have no children - These will be children of B) and then F has bit value of 1 so 1110010 00 (bold figures) will be children of F. 7th bit is 0 and so G will also be leaf node.

4) Again loop through or try recusion - From 4th,5th and 6th and 7th bits only one bit is 1 so next 2^1 bits will be in next level and those will be children of F.

Once the tree is made then converting to PostFix is easy.

0
Maurice Perry On

One possible solution (in less than an hour):

import java.util.ArrayList;
import java.util.List;

public class Main {

    private static class Node {
        private Node left;
        private Node right;
    }

    private static Node buildTree(String input) {
        char chars[] = input.toCharArray();
        if (chars.length == 0) {
            return null;
        } else {
            Node root = new Node();
            List<Node> nodeList = new ArrayList<Node>();
            nodeList.add(root);
            int pos = 0;
            while (!nodeList.isEmpty()) {
                List<Node> nextList = new ArrayList<Node>();
                for (Node n: nodeList) {
                    if (pos >= chars.length) {
                        throw new RuntimeException("Invalid input string");
                    }
                    char c = chars[pos++];
                    if (c == '1') {
                        n.left = new Node();
                        n.right = new Node();
                        nextList.add(n.left);
                        nextList.add(n.right);
                    } else if (c != '0') {
                        throw new RuntimeException("Invalid input string");
                    }
                }
                nodeList = nextList;
            }
            return root;
        }
    }

    private static String postTraverse(Node n) {
        if (n == null) {
            return "";
        } else if (n.left == null && n.right == null) {
            return "0";
        } else {
            return postTraverse(n.left) + postTraverse(n.right) + "1";
        }
    }

    public static void main(String[] args) {
        Node tree = buildTree(args[0]);
        System.out.println(postTraverse(tree));
    }
}
0
peter.petrov On

Here is a pretty simple solution. Not really optimal with
respect to memory though, as I build a complete/full tree first
and then I mark which nodes actually exist in our tree. So this
could be optimized a bit, I guess.

    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.Queue;

    class Node {
        public Node left;
        public Node right;
        public Integer id;
        public boolean exists;
    }

    public class Test32 {

        public static void main(String[] args) {
            HashMap<Integer, Node> mp = new HashMap<Integer, Node>();

            String str = "110101000";
            int sz = (int)Math.pow(2, str.length() + 1);

            for (int i=0; i<sz; i++){
                Node nd = new Node();
                nd.id = i;
                mp.put(nd.id, nd);
            }

            for (int i=0; i<sz; i++){
                Node nd = mp.get(i);
                if (2*i < sz) nd.left = mp.get(2*i + 1);
                if (2*i + 1 < sz) nd.right = mp.get(2*i + 2);
            }

            Queue<Integer> visit = new LinkedList<Integer>();
            visit.add(0); // id = 0;

            int j = 0;
            int id = -1;
            while (!visit.isEmpty()){
                id = visit.poll();
                if (str.charAt(j) == '1'){
                    mp.get(id).exists = true;
                    visit.add(2*id + 1);
                    visit.add(2*id + 2);
                }else{
                    mp.get(id).exists = true;
                }
                j++;
            }

            System.out.println("NODES:");
            for (int i=0; i<sz; i++){
                if (mp.get(i).exists){
                    System.out.println(i);
                }
            }

            System.out.println();
            System.out.println("EDGES:");
            for (int i=0; i<sz; i++){
                if (mp.get(i).exists){
                    if (mp.get(2 * i + 1).exists){
                        System.out.println(i + " --> " + (2*i+1));
                    }
                    if (mp.get(2 * i + 2).exists){
                        System.out.println(i + " --> " + (2*i+2));
                    }
                }
            }

        }

    }

And here is the same solution simplified edition.
No trees or maps, just a boolean array. If some node
k has children these children are 2*k+1 and 2*k+2.
In the last loop while printing the edges one can also
construct an actual binary tree.

    import java.util.LinkedList;
    import java.util.Queue;

    public class Test32 {

        public static void main(String[] args) {

            String str = "110101000";
            int sz = (int)Math.pow(2, str.length() + 1);
            boolean exists[] = new boolean[sz];

            Queue<Integer> visit = new LinkedList<Integer>();
            visit.add(0); // id = 0;
            if (str.charAt(0) == '1'){
                exists[0] = true;
            }

            int j = 0;
            int id = -1;
            while (!visit.isEmpty()){
                id = visit.poll();
                if (str.charAt(j) == '1'){
                    exists[id] = true;
                    visit.add(2*id + 1);
                    visit.add(2*id + 2);
                }else{
                    exists[id] = true;
                }
                j++;
            }

            // System.out.println("");
            System.out.println("NODES:");
            for (int i=0; i<sz; i++){
                if (exists[i]){
                    System.out.println(i);
                }
            }

            System.out.println("");
            System.out.println("EDGES:");
            for (int i=0; i<sz; i++){
                if (exists[i]){
                    if (exists[2*i+1]){
                        System.out.println(i + " --> " + (2*i+1));
                    }
                    if (exists[2*i+2]){
                        System.out.println(i + " --> " + (2*i+2));
                    }
                }
            }

        }

    }