9

I came across this problem that has Ternary expression (a?b:c) and needs the ternary expression to be converted into a Binary tree structure.

     a?b:c 

       a
      / \
     b   c

  a?b?c:d:e

     a
    / \
   b   e
  / \
 c   d

My approach using a Binary tree implemented using a array :-

Parent resides at - i Left child - 2i Right child - 2i+1

Start parsing the ternary expression the first character will form the root node so it will be at position 1 in the array. If the next character is a '?' then the characters that follow will be its children so left child (b in this case will be at position 2). If the next character is a ":" then we have found the right child (c in the first case) so we add that to position 3.

In the second case we face a "?" after b so whatever follows will be its children and will be added to 2j and 2j+1 respectively where j is the position of b in the array.Now we face a ":" we check the parent of the current child if it has two children then we backtrack and check the previous node until we find a node that is missing a right child.

Is there any other way to do this? Hope I have been articulate enough.

aamir23
  • 1,143
  • 15
  • 23

9 Answers9

10

Below is my solution which has been tested thoroughly.

class TreeNode {
    char c;
    TreeNode left;
    TreeNode right;

    TreeNode(char c) {
        this.c = c;
        left = null;
        right = null;
    }
}

public TreeNode tenaryToTree(String s) {
    if (s.length() == 0) {
        return null;
    }

    TreeNode root = new TreeNode(s.charAt(0));
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);

    for (int i = 1; i < s.length(); i++) {
        if (s.charAt(i) == '?') {
            TreeNode node = stack.peek();
            node.left = new TreeNode(s.charAt(i + 1));
            stack.push(node.left);
        } else if (s.charAt(i) == ':') {
            stack.pop();
            TreeNode node = stack.pop();
            node.right = new TreeNode(s.charAt(i + 1));
            stack.push(node.right);
        }
    }

    return root;
}
6324
  • 4,678
  • 8
  • 34
  • 63
2

This one would be without using parent node. But using stack.

    public NodeC convertTtoBT (char[] values) {
    char xx = values[0];
    NodeC n = new NodeC(xx);
    Stack<NodeC> a =  new Stack<NodeC>();
    for (int i = 1; i < values.length; i += 2) {
        if (values[i] == '?') {
            n.left = new NodeC (values[i + 1]);
            a.add(n);
            n = n.left;

        }
        else if (values[i] == ':') {
            n = a.pop();
            while (n.right != null) {
                n = a.pop();
            }             
            n.right = new NodeC (values[i + 1]);
            a.add(n);
            n = n.right;
        }
    }
    return n;
}
2

Walk through the expression from right to left, pushing any letters as nodes to the stack. If you see '?', then instead of pushing the next letter, take it as the root, pop two last nodes from the stack as left and right root's children, and push the root back into the stack.

public TreeNode ternaryToTree(char[] exp) {
    LinkedList<TreeNode> stack = new LinkedList<TreeNode>();

    for (int i = exp.length-1; i >= 0; i--) {
        if (exp[i] == ':') continue;
        if (exp[i] == '?') {
            TreeNode node = new TreeNode(exp[--i]);
            node.left = stack.pop();
            node.right = stack.pop();
            stack.push(node);
        } else {
            stack.push(new TreeNode(exp[i]));
        }
    }

    return stack.isEmpty() ? null : stack.pop();
}
vsg
  • 61
  • 3
  • 9
2

if this a?b:c?d?e:f:g?h:i?j:k is the ternary expression then tree would be like this

          a
         / \
        b   c
           /  \
          d    g
         / \  / \
        e   f h  i
                / \
               j   k

Below is the Java solution...

private static TreeNode convertTernaryExpression(String s) 
{

    Stack<TreeNode> stack = new Stack<>();

    int length = s.length();
    int index = 0;
    TreeNode rootNode = null;
    while(index < length)
    {
        while(s.charAt(index) != ':')
        {
            if(s.charAt(index) == '?' && stack.peek().right != null)
            {
                TreeNode temp = stack.pop();
                if(rootNode == null)
                {
                    rootNode = temp;
                }
                stack.push(temp.right);
            }
            stack.push(new TreeNode(s.charAt(index++)));
        }

        TreeNode left = stack.pop();
        TreeNode questionMark = stack.pop();
        TreeNode root = stack.pop();
        index++;
        TreeNode right = new TreeNode(s.charAt(index++));

        root.left = left;
        root.right = right;

        stack.push(root);
    }

    if(rootNode == null)
    {
        return stack.pop();
    }
    else
    {
        return rootNode;
    }
}

class TreeNode
{
    TreeNode left;
    TreeNode right;
    char val;
    public TreeNode(char val) 
    {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}
1

I came up with something like this using trees. Not tested thoroughly:

When I see a '?', it's my left child, so add to my left and go left.

If I see ':', then:

  1. Go to my parent
  2. If right is not null and parent is not not null, keep going to my parent
  3. My right child is empty. Add right. Go to right.

Note: You will never go back to the root if it has a right child.

    public NodeC convertTtoBT (char[] values) {
    NodeC n = new NodeC (values[0]);

    for (int i = 1; i < values.length; i += 2) {
        if (values[i] == '?') {
            n.left = new NodeC (values[i + 1]);
            n = n.left;
        }
        else if (values[i] == ':') {
            n = n.parent;
            while (n.right != null && n.parent != null ) {
                n = n.parent;
            }                    
            n.right = new NodeC (values[i + 1]);
            n = n.right;
        }
    }
    return n;
Adnan Z
  • 394
  • 3
  • 10
1

Idea is to start parsing the string from left to right and when you come across a '?' you go deeper in the tree else just return the new node created.

Here is my recursive solution :

  struct node{
    char val;
    node *left;
    node *right;
    node(char v):val(v),left(NULL),right(NULL){
    }
};

    node* create_tree(string input, int &current){
    if(current>=(int)input.size()){
        return NULL;
    }
    node *temp = new node(input[current]);
    current+=2;
    if(current<(int)input.size()){
        if(input[current-1]=='?'){
            temp->left=create_ternary_tree(input,current);
            temp->right=create_ternary_tree(input,current);
        }
    }
    return temp;
}
Viraj
  • 777
  • 1
  • 13
  • 32
1

My solution: Each treenode doen't have parent link, so I use stack to keep them. The advantages of this solution are that I only push root into stack, hence in the (if x==':' {}) sentence, no while loop, no push sentence.

    public  static TreeNode convert(String ternary) {
    char[] chs = ternary.toCharArray();
    Stack<TreeNode> stack = new Stack<TreeNode>();
    TreeNode cur=new TreeNode(chs[0]);
    TreeNode root= cur;
    for (int i=1; i<chs.length; i+=2) {
        if (chs[i]=='?') {
            stack.push(cur);
            TreeNode node = new TreeNode(chs[i+1]);
            cur.left = node;
            cur = node;
        }
        else if (chs[i]==':') {
            cur = stack.pop();
            TreeNode node = new TreeNode(chs[i+1]);
            cur.right = node;
            cur = node;

        }
    }
    return root;
}
0
 public static TreeNode convert_loop(char[] expr) {
    if (expr == null || expr.length < 1) {
        return null;
    }
    if (expr.length == 1) {
        return new TreeNode(expr[0]);
    }
    if ((expr.length - 1) % 4 != 0) {
        throw new InputMismatchException("wrong expression");
    }
    int start = 0, end = expr.length - 1;

    TreeNode<Character> root = new TreeNode<>(expr[start]);
    root.right = new TreeNode<>(expr[end]);

    start += 2;
    end -= 2;
    TreeNode<Character> cur = root;

    while (start != end) {
        TreeNode<Character> node = new TreeNode<>(expr[start]);
        node.right = new TreeNode<>(expr[end]);

        cur.left = node;
        cur = node;

        start += 2;
        end -= 2;
    }
    cur.left = new TreeNode(expr[start]);// care
    return root;
}
Bruce Zu
  • 507
  • 6
  • 17
0

Following is the python implementation, the idea is to traverse the string from left to right, if you come across '?' then push the most recent node in the stack and use it as a parent and pop a node from the stack when ':' is encountered, and in other cases simply assign the current node to left or right of parent pointer.

from collections import deque

class Node:

    def __init__(self , left = None, right = None, val = None):
        self.left = left
        self.right = right
        self.val = val


def makeTree(s:str):
    stack = deque()
    root = Node(val = s[0])
    stack.append(root)
    prev = None
    for i,char in enumerate(s[1:]):
        if char == '?':
            if i != 0:
                stack.append(prev) 
            parent = stack[-1]
        elif char == ':':
            parent = stack.pop()
        else:

            if parent.left == None:
                parent.left = Node(val = char)
                prev = parent.left
           
             else:

                parent.right = Node(val=char)
                prev = parent.right
    return root

def preorder(root):
    if root == None:
        return

    print(root.val,end=' ')
    preorder(root.left)
    preorder(root.right)


ternary = 'a?b?d:e:c'
r=makeTree(ternary)
preorder(r)