1、算法的主要思想就是将一个中缀表达式(Infix expression)转换成便于处理的后缀表达式(Postfix expression),然后借助于栈这个简单的数据结构,计算出表达式的结果。
Test No.1: (1.11)=1.110000
Test No.2:1.11+2.22-3.33*4.44/5.55=0.666000
Test No.3:1.11+(2.22-3.33)*4.44/5.55=0.222000
Test No.4:1.11+(2.22-3.33)*(4.44+5.55)/6.66=-0.555000
Test No.5:1.11*((2.22-3.33)*(4.44+5.55))/(6.66+7.77)=-0.852992
Test No.6: (1.11+2.22)*(3.33+4.44)/5.55*6.66=31.048920
Test No.7: (1.11-2.22)/(3.33+4.44)/5.55*(6.66+7.77)/(8.88)=-0.041828
Test No.8: Error: (1.11+2.22)*(3.33+4.44: missing")", please check your expression
Test No.9: Error: (1.11+2.22)*3.33/0+(34-45): divisor cannot be zero
Test No.10: Error:12+89^7: invalid character: ^
classStack(object):
"""
The structure of a Stack.
The user don't have to know the definition.
"""
def__init__(self):
self.__container=list()
def__is_empty(self):
"""
Test if the stack is empty or not
:return: True or False
"""
returnlen(self.__container)==0
defpush(self, element):
"""
Add a new element to the stack
:param element: the element you want to add
:return: None
"""
self.__container.append(element)
deftop(self):
"""
Get the top element of the stack
:return: top element
"""
ifself.__is_empty():
returnNone
returnself.__container[-1]
defpop(self):
"""
Remove the top element of the stack
:return: None or the top element of the stack
"""
returnNoneifself.__is_empty()elseself.__container.pop()
defclear(self):
"""
We'll make an empty stack
:return: self
"""
self.__container.clear()
returnself
在计算器类中,我们将表达式的合法性验证单独放在一个函数中完成,但是实际上如果需要,也可以直接放在中缀表达式转后缀表达式的函数中实现,这样只需要一次遍历表达式即可同时完成验证和转换工作。但是为了保持结构清晰,还是分开来实现比较好,每个函数尽可能最好一件事情才是比较实在的。
在该计算器类中,有很多种极端的情况没有被考虑进去,因为那样的话整个实现的代码会更多。不过,可以在后期为整个类继续扩展,添加新的功能也是可以的。目前实现的就是主要框架,包括基本的错误检测和运算,重点时学习运用栈这个看似简单却强大的数据结构解决问题。
classCalculator(object):
"""
A simple calculator, just for fun
"""
def__init__(self):
self.__exp=''
def__validate(self):
"""
We have to make sure the expression is legal.
1. We only accept the `()` to specify the priority of a sub-expression. Notes: `[ {` and `] }` will be
replaced by `(` and `)` respectively.
2. Valid characters should be `+`, `-`, `*`, `/`, `(`, `)` and numbers(int, float)
- Invalid expression examples, but we can only handle the 4th case. The implementation will
be much more sophisticated if we want to handle all the possible cases.:
1. `a+b-+c`
2. `a+b+-`
3. `a+(b+c`
4. `a+(+b-)`
5. etc
:return: True or False
"""
ifnotisinstance(self.__exp,str):
print('Error: {}: expression should be a string'.format(self.__exp))
returnFalse
# Save the non-space expression
val_exp=''
s=Stack()
forxinself.__exp:
# We should ignore the space characters
ifx==' ':
continue
ifself.__is_bracket(x)orself.__is_digit(x)orself.__is_operators(x) \
orx=='.':
ifx=='(':
s.push(x)
elifx==')':
s.pop()
val_exp+=x
else:
print('Error: {}: invalid character: {}'.format(self.__exp, x))
returnFalse
ifs.top():
print('Error: {}: missing ")", please check your expression'.format(self.__exp))
returnFalse
self.__exp=val_exp
returnTrue
def__convert2postfix_exp(self):
"""
Convert the infix expression to a postfix expression
:return: the converted expression
"""
# highest priority: ()
# middle: * /
# lowest: + -
converted_exp=''
stk=Stack()
forxinself.__exp:
ifself.__is_digit(x)orx=='.':
converted_exp+=x
elifself.__is_operators(x):
converted_exp+=' '
tp=stk.top()
iftp:
iftp=='(':
stk.push(x)
continue
x_pri=self.__get_priority(x)
tp_pri=self.__get_priority(tp)
ifx_pri > tp_pri:
stk.push(x)
elifx_pri==tp_pri:
converted_exp+=stk.pop()+' '
stk.push(x)
else:
whilestk.top():
ifself.__get_priority(stk.top()) !=x_pri:
converted_exp+=stk.pop()+' '
else:
break
stk.push(x)
else:
stk.push(x)
elifself.__is_bracket(x):
converted_exp+=' '
ifx=='(':
stk.push(x)
else:
whilestk.top()andstk.top() !='(':
converted_exp+=stk.pop()+' '
stk.pop()
# pop all the operators
whilestk.top():
converted_exp+=' '+stk.pop()+' '
returnconverted_exp
def__get_result(self, operand_2, operand_1, operator):
ifoperator=='+':
returnoperand_1+operand_2
elifoperator=='-':
returnoperand_1-operand_2
elifoperator=='*':
returnoperand_1*operand_2
elifoperator=='/':
ifoperand_2 !=0:
returnoperand_1/operand_2
else:
print('Error: {}: divisor cannot be zero'.format(self.__exp))
returnNone
def__calc_postfix_exp(self, exp):
"""
Get the result from a converted postfix expression
e.g. 6 5 2 3 + 8 * + 3 + *
:return: result
"""
assertisinstance(exp,str)
stk=Stack()
exp_split=exp.strip().split()
forxinexp_split:
ifself.__is_operators(x):
# pop two top numbers in the stack
r=self.__get_result(stk.pop(), stk.pop(), x)
ifrisNone:
returnNone
else:
stk.push(r)
else:
# push the converted number to the stack
stk.push(float(x))
returnstk.pop()
def__calc(self):
"""
Try to get the result of the expression
:return: None or result
"""
# Validate
ifself.__validate():
# Convert, then run the algorithm to get the result
returnself.__calc_postfix_exp(self.__convert2postfix_exp())
else:
returnNone
defget_result(self, expression):
"""
Get the result of an expression
Suppose we have got a valid expression
:return: None or result
"""
self.__exp=expression.strip()
returnself.__calc()
"""
Utilities
"""
@staticmethod
def__is_operators(x):
returnxin['+','-','*','/']
@staticmethod
def__is_bracket(x):
returnxin['(',')']
@staticmethod
def__is_digit(x):
returnx.isdigit()
@staticmethod
def__get_priority(op):
ifopin['+','-']:
return0
elifopin['*','/']:
return1