堆栈实现四则运算(一)
Jupyter Notebook 实现
前缀、中缀和后缀表达式
表达式分为前缀表达式,中缀表达式和后缀表达式。
- 中缀表达式指我们日常看到的运算表达式,例如:2*3-4/6
- 前缀表达式指将中缀表达式根据优先级进行二叉树前序遍历得到的表达式,例如:- * 2 3 / 4 6
- 后缀表达式指将前缀表达式根据优先级进行二叉树后序遍历得到的表达式,例如:2 3 * 4 6 / -
基本思路
堆栈是一种“FILO(先进后出)”的线性数据结构,利用该特点实现基本四则运算
- 定义堆栈数据结构,包括一些基本的压栈和弹出等操作;
- 定义运算符的优先级;
- 定义计算函数,参数为一个操作符(operator)和两个操作数(operand),功能为实现一次运算;
- 定义我们的目标函数:
for循环扫描运算表达式:
如果是数字,压入operands_stack;
如果是操作符,判断优先级,优先级高可以放进operators_stack中;
如果是左括号,压入operators_stack;
如果是右括号,在operators_stack中寻找左括号,
如果是其他:表示暂不支持
while循环计算最终结果:
如果operands_stack中只有一个元素,那这个元素就是表达式的运算结果;
如果多于一个元素,需要再运算得到最终结果;
代码
#定义堆栈
class Stack:
def __init__(self):
self.items=[]
def is_empty(self): #判断栈是否为空
return self.items == []
def push(self,item): #压入
self.items.append(item)
def pop(self): #弹出
return self.items.pop()
def peek(self): #返回栈顶元素
return self.items[len(self.items)-1]
def size(self): #返回栈的元素个数
return len(self.items)
#定义比较优先级函数
def compare_prec(oper1,oper2):
#字典保存操作符的优先级
prec={}
prec["*"]=3
prec["/"]=3
prec["+"]=2
prec["-"]=2
if prec[oper1]<prec[oper2]:
return True
else:
return False
#定义计算函数
def do_math(op,op1,op2):
if op =="*":
return op1*op2
elif op =="/":
if op2 == 0:
return "none"
else:
return op1/op2
elif op =="+":
return op1+op2
else:
return op1-op2
#定义目标函数
import jieba
def infix_evaluator(infix_expr):
infix_list = jieba.lcut(infix_expr) #分解运算式
#定义两个堆栈
operators_stack = Stack() #存放操作符
operands_stack =Stack() #存放操作数
#扫描与计算
for token in infix_list:
if token in ( " ".join( [str(i) for i in range(100)] ) ):
operands_stack.push( eval(token) )
elif token == "(":
operators_stack.push( token ) #左括号在表达式中优先级最高,放入栈中优先级为最低,但操作数不与其比较优先级
elif token == ")":
while operators_stack.peek() != "(":
op = operators_stack.pop() #弹出操作符
op2 =operands_stack.pop() #弹出两个操作数
op1 =operands_stack.pop()
result = do_math(op,op1,op2)
if result == "none":
return "Divisor can not be zero!"
operands_stack.push( result) #运算结果再压栈
operators_stack.pop()
elif token in "+-*/":
if operators_stack.is_empty():
operators_stack.push( token )
else:
if operators_stack.peek()!= "(":
if compare_prec( token,operators_stack.peek() ): #token 优先级小
op = operators_stack.pop()
op2 =operands_stack.pop()
op1 =operands_stack.pop()
result = do_math(op,op1,op2 )
if result == "none":
return "Divisor can not be zero!"
operands_stack.push( result)
operators_stack.push( token )
else:
return "expression is wrong!"
while operands_stack.size() >1:
op = operators_stack.pop()
op2 =operands_stack.pop()
op1 =operands_stack.pop()
result = do_math(op,op1,op2)
operands_stack.push( result)
return operands_stack.pop()
if __name__ == "__main__":
in_string = input("please input your expression:") #输入运算表达式
print( infix_evaluator(in_string) )
问题
- 程序有些冗杂,日后再进行改进;
- 存在一些特殊情况,该程序可能会报错
- 堆栈实现四则运算另一种思路是将表达式转化为后缀表达式,再对后缀表达式进行运算,该方法需要一个栈但需要扫描两次表达式。
- 该程序是利用两个堆栈,只扫描一次。