Skip to content

Commit e4e4fc4

Browse files
committed
add expression.py
1 parent 333870e commit e4e4fc4

File tree

2 files changed

+197
-1
lines changed

2 files changed

+197
-1
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@ ALl the problems please refer to http://oj.leetcode.com/problems/
66

77
The problem descriptions are also included in each python file.
88

9-

expression.py

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#!/usr/bin/env python
2+
'''
3+
Q: Infix, postfix, and prefix expression conversion and evaluation
4+
For example:
5+
Infix: 1 * (2 + 3) / 4
6+
Postfix: 1 2 3 + * 4 /
7+
Prefix: / * 1 + 2 3 4
8+
9+
Build up a binary tree with numbers as leaves and operators as internal nodes.
10+
In-order traversal → infix
11+
Post-order traversal → postfix
12+
Pre-order traversal → prefix
13+
'''
14+
from __future__ import division
15+
import random
16+
17+
18+
OPERATORS = set(['+', '-', '*', '/', '(', ')'])
19+
PRIORITY = {'+':1, '-':1, '*':2, '/':2}
20+
21+
22+
### INFIX ===> POSTFIX ###
23+
'''
24+
1)Fix a priority level for each operator. For example, from high to low:
25+
3. - (unary negation)
26+
2. * /
27+
1. + - (subtraction)
28+
2) If the token is an operand, do not stack it. Pass it to the output.
29+
3) If token is an operator or parenthesis:
30+
3.1) if it is '(', push
31+
3.2) if it is ')', pop until '('
32+
3.3) push the incoming operator if its priority > top operator; otherwise pop.
33+
*The popped stack elements will be written to output.
34+
4) Pop the remainder of the stack and write to the output (except left parenthesis)
35+
'''
36+
def infix_to_postfix(formula):
37+
stack = [] # only pop when the coming op has priority
38+
output = ''
39+
for ch in formula:
40+
if ch not in OPERATORS:
41+
output += ch
42+
elif ch == '(':
43+
stack.append('(')
44+
elif ch == ')':
45+
while stack and stack[-1] != '(':
46+
output += stack.pop()
47+
stack.pop() # pop '('
48+
else:
49+
while stack and stack[-1] != '(' and PRIORITY[ch] <= PRIORITY[stack[-1]]:
50+
output += stack.pop()
51+
stack.append(ch)
52+
# leftover
53+
while stack: output += stack.pop()
54+
print output
55+
return output
56+
57+
58+
### POSTFIX ===> INFIX ###
59+
'''
60+
1) When see an operand, push
61+
2) When see an operator, pop out two numbers, connect them into a substring and push back to the stack
62+
3) the top of the stack is the final infix expression.
63+
'''
64+
def postfix_to_infix(formula):
65+
stack = []
66+
prev_op = None
67+
for ch in formula:
68+
if not ch in OPERATORS:
69+
stack.append(ch)
70+
else:
71+
b = stack.pop()
72+
a = stack.pop()
73+
if prev_op and len(a) > 1 and PRIORITY[ch] > PRIORITY[prev_op]:
74+
# if previous operator has lower priority
75+
# add '()' to the previous a
76+
expr = '('+a+')' + ch + b
77+
else:
78+
expr = a + ch + b
79+
stack.append(expr)
80+
prev_op = ch
81+
print stack[-1]
82+
return stack[-1]
83+
84+
85+
### INFIX ===> PREFIX ###
86+
def infix_to_prefix(formula):
87+
op_stack = []
88+
exp_stack = []
89+
for ch in formula:
90+
if not ch in OPERATORS:
91+
exp_stack.append(ch)
92+
elif ch == '(':
93+
op_stack.append(ch)
94+
elif ch == ')':
95+
while op_stack[-1] != '(':
96+
op = op_stack.pop()
97+
a = exp_stack.pop()
98+
b = exp_stack.pop()
99+
exp_stack.append( op+b+a )
100+
op_stack.pop() # pop '('
101+
else:
102+
while op_stack and op_stack[-1] != '(' and PRIORITY[ch] <= PRIORITY[op_stack[-1]]:
103+
op = op_stack.pop()
104+
a = exp_stack.pop()
105+
b = exp_stack.pop()
106+
exp_stack.append( op+b+a )
107+
op_stack.append(ch)
108+
109+
# leftover
110+
while op_stack:
111+
op = op_stack.pop()
112+
a = exp_stack.pop()
113+
b = exp_stack.pop()
114+
exp_stack.append( op+b+a )
115+
print exp_stack[-1]
116+
return exp_stack[-1]
117+
118+
119+
### PREFIX ===> INFIX ###
120+
'''
121+
Scan the formula reversely
122+
1) When the token is an operand, push into stack
123+
2) When the token is an operator, pop out 2 numbers from stack, merge them and push back to the stack
124+
'''
125+
def prefix_to_infix(formula):
126+
stack = []
127+
prev_op = None
128+
for ch in reversed(formula):
129+
if not ch in OPERATORS:
130+
stack.append(ch)
131+
else:
132+
a = stack.pop()
133+
b = stack.pop()
134+
if prev_op and PRIORITY[prev_op] < PRIORITY[ch]:
135+
exp = '('+a+')'+ch+b
136+
else:
137+
exp = a+ch+b
138+
stack.append(exp)
139+
prev_op = ch
140+
print stack[-1]
141+
return stack[-1]
142+
143+
144+
'''
145+
Scan the formula:
146+
1) When the token is an operand, push into stack;
147+
2) When an operator is encountered:
148+
2.1) If the operator is binary, then pop the stack twice
149+
2.2) If the operator is unary (e.g. unary minus), pop once
150+
3) Perform the indicated operation on two poped numbers, and push the result back
151+
4) The final result is the stack top.
152+
'''
153+
def evaluate_postfix(formula):
154+
stack = []
155+
for ch in formula:
156+
if ch not in OPERATORS:
157+
stack.append(float(ch))
158+
else:
159+
b = stack.pop()
160+
a = stack.pop()
161+
c = {'+':a+b, '-':a-b, '*':a*b, '/':a/b}[ch]
162+
stack.append(c)
163+
print stack[-1]
164+
return stack[-1]
165+
166+
167+
def evaluate_infix(formula):
168+
return evaluate_postflix(inflix_to_postfix(formula))
169+
170+
171+
''' Whenever we see an operator following by two numbers,
172+
we can compute the result.'''
173+
def evaluate_prefix(formula):
174+
exps = list(formula)
175+
while len(exps) > 1:
176+
for i in range(len(exps)-2):
177+
if exps[i] in OPERATORS:
178+
if not exps[i+1] in OPERATORS and not exps[i+2] in OPERATORS:
179+
op, a, b = exps[i:i+3]
180+
a,b = map(float, [a,b])
181+
c = {'+':a+b, '-':a-b, '*':a*b, '/':a/b}[op]
182+
exps = exps[:i] + [c] + exps[i+3:]
183+
break
184+
print exps
185+
return exps[-1]
186+
187+
188+
if __name__ == '__main__':
189+
#infix_to_postfix('1+(3+4*6+6*1)*2/3')
190+
#infix_to_prefix('1+(3+4*6+6*1)*2/3')
191+
print
192+
#evaluate_inflix('1+(3+4*6+6*1)*2/3')
193+
#evaluate_postfix('1346*+61*+2*3/+')
194+
#evaluate_prefix('+1/*++3*46*6123')
195+
print
196+
#postfix_to_infix('1346*+61*+2*3/+')
197+
prefix_to_infix('+1/*++3*46*6123')

0 commit comments

Comments
 (0)