Given a string representing infix notation. The task is to convert it to an expression tree.
Expression Tree is a binary tree where the operands are represented by leaf nodes and operators are represented by intermediate nodes. No node can have a single child.
Construction of Expression tree
The algorithm follows a combination of shunting yard along with postfix-to-expression tree conversion.
Consider the below line:
((s[i]!='^' && p[stC.top()]>=p[s[i]]) ||
(s[i]=='^' && p[stC.top()]>p[s[i]])))
You might remember that unlike ‘+’, ‘-‘, ‘*’ and ‘/’; ‘^’ is right associative.
In simpler terms, a^b^c is a^(b^c) not (a^b)^c. So it must be evaluated from the right.
Now lets take a look at how does the algorithm work,(Take a quick glance at the code to get a better idea of the variables used)
Let us have an expression s = ((a+b)*c-e*f)
currently both the stacks are empty-
(we'll use C to denote the char stack and N for node stack)
s[0] = '(' ((a+b)*c-e*f)
^
C|(|, N| |
s[1] = '(' ((a+b)*c-e*f)
^
|(|
C|(|, N| |
s[2] = 'a' ((a+b)*c-e*f)
^
|(|
C|(|, N|a|
s[3] = '+' ((a+b)*c-e*f)
^
|+|
|(|
C|(|, N|a|
s[4] = 'b' ((a+b)*c-e*f)
^
|+|
|(| |b|
C|(|, N|a|
s[5] = ')' ((a+b)*c-e*f)
^
|+| t = '+' +
|(| |b| -> t1= 'b' / \ ->
C|(|, N|a| t2= 'a' a b C|(|, N|+|
s[6] = '*' ((a+b)*c-e*f)
^
|*|
C|(|, N|+|
s[7] = 'c' ((a+b)*c-e*f)
^
|*| |c|
C|(|, N|+|
s[8] = '-' ((a+b)*c-e*f) now (C.top(*)>s[8](-))
^ t = '*' *
|*| |c| t1 = c / \ -> |-|
C|(|, N|+| t2 = + + c C|(|, N|*|
/ \
a b
s[9] = 'e' ((a+b)*c-e*f)
^
|-| |e|
C|(|, N|*|
s[10] = '*' ((a+b)*c-e*f) now (C.top(-)>s[10](*))
^
|*|
|-| |e|
C|(|, N|*|
s[11] = 'f' ((a+b)*c-e*f)
^
|*| |f|
|-| |e|
C|(|, N|*|
s[12] = ')' ((a+b)*c-e*f)
1> ^
|*| |f| t = '*' *
|-| |e| -> t1= 'f' -> / \ -> |-| |*|
C|(|, N|*| t2= 'e' e f C|(|, N|*|
2>
t = '-' -
|-| |*| -> t1= '*' -> / \ ->
C|(|, N|*| t2= '*' * * C| |, N|-|
/ \ / \
+ c e f
/ \
a b
now make (-) the root of the tree
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
typedef struct node
{
char data;
struct node *left, *right;
} * nptr;
nptr newNode( char c)
{
nptr n = new node;
n->data = c;
n->left = n->right = nullptr;
return n;
}
nptr build(string& s)
{
stack<nptr> stN;
stack< char > stC;
nptr t, t1, t2;
int p[123] = { 0 };
p[ '+' ] = p[ '-' ] = 1, p[ '/' ] = p[ '*' ] = 2, p[ '^' ] = 3,
p[ ')' ] = 0;
for ( int i = 0; i < s.length(); i++)
{
if (s[i] == '(' ) {
stC.push(s[i]);
}
else if ( isalpha (s[i]))
{
t = newNode(s[i]);
stN.push(t);
}
else if (p[s[i]] > 0)
{
while (
!stC.empty() && stC.top() != '('
&& ((s[i] != '^' && p[stC.top()] >= p[s[i]])
|| (s[i] == '^'
&& p[stC.top()] > p[s[i]])))
{
t = newNode(stC.top());
stC.pop();
t1 = stN.top();
stN.pop();
t2 = stN.top();
stN.pop();
t->left = t2;
t->right = t1;
stN.push(t);
}
stC.push(s[i]);
}
else if (s[i] == ')' ) {
while (!stC.empty() && stC.top() != '(' )
{
t = newNode(stC.top());
stC.pop();
t1 = stN.top();
stN.pop();
t2 = stN.top();
stN.pop();
t->left = t2;
t->right = t1;
stN.push(t);
}
stC.pop();
}
}
t = stN.top();
return t;
}
void postorder(nptr root)
{
if (root)
{
postorder(root->left);
postorder(root->right);
cout << root->data;
}
}
int main()
{
string s = "(a^b^(c/d/e-f)^(x*y-m*n))" ;
s = "(" + s;
s += ")" ;
nptr root = build(s);
postorder(root);
return 0;
}
|
Java
import java.util.*;
class GFG
{
static class nptr
{
char data;
nptr left, right;
} ;
static nptr newNode( char c)
{
nptr n = new nptr();
n.data = c;
n.left = n.right = null ;
return n;
}
static nptr build(String s)
{
Stack<nptr> stN = new Stack<>();
Stack<Character> stC = new Stack<>();
nptr t, t1, t2;
int []p = new int [ 123 ];
p[ '+' ] = p[ '-' ] = 1 ;
p[ '/' ] = p[ '*' ] = 2 ;
p[ '^' ] = 3 ;
p[ ')' ] = 0 ;
for ( int i = 0 ; i < s.length(); i++)
{
if (s.charAt(i) == '(' ) {
stC.add(s.charAt(i));
}
else if (Character.isAlphabetic(s.charAt(i)))
{
t = newNode(s.charAt(i));
stN.add(t);
}
else if (p[s.charAt(i)] > 0 )
{
while (
!stC.isEmpty() && stC.peek() != '('
&& ((s.charAt(i) != '^' && p[stC.peek()] >= p[s.charAt(i)])
|| (s.charAt(i) == '^'
&& p[stC.peek()] > p[s.charAt(i)])))
{
t = newNode(stC.peek());
stC.pop();
t1 = stN.peek();
stN.pop();
t2 = stN.peek();
stN.pop();
t.left = t2;
t.right = t1;
stN.add(t);
}
stC.push(s.charAt(i));
}
else if (s.charAt(i) == ')' ) {
while (!stC.isEmpty() && stC.peek() != '(' )
{
t = newNode(stC.peek());
stC.pop();
t1 = stN.peek();
stN.pop();
t2 = stN.peek();
stN.pop();
t.left = t2;
t.right = t1;
stN.add(t);
}
stC.pop();
}
}
t = stN.peek();
return t;
}
static void postorder(nptr root)
{
if (root != null )
{
postorder(root.left);
postorder(root.right);
System.out.print(root.data);
}
}
public static void main(String[] args)
{
String s = "(a^b^(c/d/e-f)^(x*y-m*n))" ;
s = "(" + s;
s += ")" ;
nptr root = build(s);
postorder(root);
}
}
|
Python3
class nptr:
def __init__( self , c):
self .data = c
self .left = None
self .right = None
def newNode(c):
n = nptr(c)
return n
def build(s):
stN = []
stC = []
p = [ 0 ] * ( 123 )
p[ ord ( '+' )] = p[ ord ( '-' )] = 1
p[ ord ( '/' )] = p[ ord ( '*' )] = 2
p[ ord ( '^' )] = 3
p[ ord ( ')' )] = 0
for i in range ( len (s)):
if (s[i] = = '(' ):
stC.append(s[i])
elif (s[i].isalpha()):
t = newNode(s[i])
stN.append(t)
elif (p[ ord (s[i])] > 0 ):
while ( len (stC) ! = 0 and stC[ - 1 ] ! = '(' and ((s[i] ! = '^' and p[ ord (stC[ - 1 ])] > = p[ ord (s[i])])
or (s[i] = = '^' and
p[ ord (stC[ - 1 ])] > p[ ord (s[i])]))):
t = newNode(stC[ - 1 ])
stC.pop()
t1 = stN[ - 1 ]
stN.pop()
t2 = stN[ - 1 ]
stN.pop()
t.left = t2
t.right = t1
stN.append(t)
stC.append(s[i])
elif (s[i] = = ')' ):
while ( len (stC) ! = 0 and stC[ - 1 ] ! = '(' ):
t = newNode(stC[ - 1 ])
stC.pop()
t1 = stN[ - 1 ]
stN.pop()
t2 = stN[ - 1 ]
stN.pop()
t.left = t2
t.right = t1
stN.append(t)
stC.pop()
t = stN[ - 1 ]
return t
def postorder(root):
if (root ! = None ):
postorder(root.left)
postorder(root.right)
print (root.data, end = "")
s = "(a^b^(c/d/e-f)^(x*y-m*n))"
s = "(" + s
s + = ")"
root = build(s)
postorder(root)
|
C#
using System;
using System.Collections.Generic;
class GFG
{
public class nptr
{
public char data;
public nptr left, right;
} ;
static nptr newNode( char c)
{
nptr n = new nptr();
n.data = c;
n.left = n.right = null ;
return n;
}
static nptr build(String s)
{
Stack<nptr> stN = new Stack<nptr>();
Stack< char > stC = new Stack< char >();
nptr t, t1, t2;
int []p = new int [123];
p[ '+' ] = p[ '-' ] = 1;
p[ '/' ] = p[ '*' ] = 2;
p[ '^' ] = 3;
p[ ')' ] = 0;
for ( int i = 0; i < s.Length; i++)
{
if (s[i] == '(' )
{
stC.Push(s[i]);
}
else if ( char .IsLetter(s[i]))
{
t = newNode(s[i]);
stN.Push(t);
}
else if (p[s[i]] > 0)
{
while (stC.Count != 0 && stC.Peek() != '('
&& ((s[i] != '^' && p[stC.Peek()] >= p[s[i]])
|| (s[i] == '^' && p[stC.Peek()] > p[s[i]])))
{
t = newNode(stC.Peek());
stC.Pop();
t1 = stN.Peek();
stN.Pop();
t2 = stN.Peek();
stN.Pop();
t.left = t2;
t.right = t1;
stN.Push(t);
}
stC.Push(s[i]);
}
else if (s[i] == ')' )
{
while (stC.Count != 0 && stC.Peek() != '(' )
{
t = newNode(stC.Peek());
stC.Pop();
t1 = stN.Peek();
stN.Pop();
t2 = stN.Peek();
stN.Pop();
t.left = t2;
t.right = t1;
stN.Push(t);
}
stC.Pop();
}
}
t = stN.Peek();
return t;
}
static void postorder(nptr root)
{
if (root != null )
{
postorder(root.left);
postorder(root.right);
Console.Write(root.data);
}
}
public static void Main(String[] args)
{
String s = "(a^b^(c/d/e-f)^(x*y-m*n))" ;
s = "(" + s;
s += ")" ;
nptr root = build(s);
postorder(root);
}
}
|
Javascript
<script>
class nptr
{
constructor(c) {
this .left = null ;
this .right = null ;
this .data = c;
}
}
function newNode(c)
{
let n = new nptr(c);
return n;
}
function build(s)
{
let stN = [];
let stC = [];
let t, t1, t2;
let p = new Array(123);
p[ '+' .charCodeAt()] = p[ '-' .charCodeAt()] = 1;
p[ '/' .charCodeAt()] = p[ '*' .charCodeAt()] = 2;
p[ '^' .charCodeAt()] = 3;
p[ ')' .charCodeAt()] = 0;
for (let i = 0; i < s.length; i++)
{
if (s[i] == '(' )
{
stC.push(s[i]);
}
else if ((/[a-zA-Z]/).test(s[i]))
{
t = newNode(s[i]);
stN.push(t);
}
else if (p[s[i].charCodeAt()] > 0)
{
while (stC.length != 0 && stC[stC.length - 1] != '('
&& ((s[i] != '^' &&
p[stC[stC.length - 1].charCodeAt()] >=
p[s[i].charCodeAt()])
|| (s[i] == '^' &&
p[stC[stC.length - 1].charCodeAt()] >
p[s[i].charCodeAt()])))
{
t = newNode(stC[stC.length - 1]);
stC.pop();
t1 = stN[stN.length - 1];
stN.pop();
t2 = stN[stN.length - 1];
stN.pop();
t.left = t2;
t.right = t1;
stN.push(t);
}
stC.push(s[i]);
}
else if (s[i] == ')' )
{
while (stC.length != 0 &&
stC[stC.length - 1] != '(' )
{
t = newNode(stC[stC.length - 1]);
stC.pop();
t1 = stN[stN.length - 1];
stN.pop();
t2 = stN[stN.length - 1];
stN.pop();
t.left = t2;
t.right = t1;
stN.push(t);
}
stC.pop();
}
}
t = stN[stN.length - 1];
return t;
}
function postorder(root)
{
if (root != null )
{
postorder(root.left);
postorder(root.right);
document.write(root.data);
}
}
let s = "(a^b^(c/d/e-f)^(x*y-m*n))" ;
s = "(" + s;
s += ")" ;
let root = build(s);
postorder(root);
</script>
|
Outputabcd/e/f-xy*mn*-^^^
The time Complexity is O(n) as each character is accessed only once.
The space Complexity is O(n) as (char_stack + node_stack) <= n