python 栈-解析四则运算公式
1、栈
栈也被称为下堆栈, 他是有序集合, 添加操作和移除操作发生在同一端,即顶端, 另一端称为底端
- LIFO(last-in, first-out) 后进先出
- 可用于反转排列顺序
栈的抽象数据类型
支持以下操作
- push(item) 将元素添加到栈中
- pop() 返回并删除顶端的元素
- peek() 返回顶端的元素, 但不删除元素
- isEmpty() 判断栈是否为空
- size() 返回栈中的元素数量
解析算数表达式
- 括号匹配: 每一个左括号都有与之对应的又括号, 并且括号有正确的嵌套关系
处理括号匹配
由空栈开始,从左往右依次处理括号。遇到左括号, 使用push操作将其加入栈中;如果遇到右括号就调用pop操作, 所有的左括号都应有右括号与之匹配。
处理完括号匹配,栈应该是空的
-
前序表达式:运算符调整到两个操作数前, eg: +ab
-
中序表达式:运算符出现在两个操作数间, eg: a*b
-
后序表达式:运算符调整至操作数后, eg: ab+
-
完全括号表达式: 对每一对运算符都添加一对括号, 由括号决定运算顺序, 杜绝歧义, 并且不需要记忆运算规则
中序表达式 前序表达式 后序表达式 a + b + a b a b + a - b / c - a / b c a b c / - a + b * c + d + a * b c + d a b c * + d + (a + b) * ( c + d) * + a b + c d a b + c d + *
中序转后序
- 创建一个空栈和列表, 分别保存运算符和转换结果列表
- 将中序表达式转换为一个列表
- 从左往右扫描列表
- 数值, 添加至转换列表中
- 左括号, 压入栈中
- 右括号, 重复从栈中获取元素,添加至转换结果列表中, 直至获取左括号
- 运算符,将其与栈中的顶端元素比较,从栈中取出优先级高的元素追加至转换列表中
- 处理完表达式后将栈中残余的运算符追加至转换结果列表中
后序表达式计算
- 创建空栈
- 将后续表达式转化为一个列表
- 从左往右扫描列表
- 数值,压入栈中
- 运算符,从栈中去两个元素, 第一个为右数, 第二个为左数,计算出数值后重新压入栈中
- 处理完表达式后, 从栈中获取数值
2、解析四则运算-Coding
后序表达式计算
# -*- coding: utf-8 -*-
"""
中序表达式转后序表达式, 并计算
"""
import re
import operator
import string
class PostOrderConversion:
def conversionToPostOrder(self, inOrdErexpr):
"""
后序转换
"""
# 构建运算符优先级字典
prec = {
"*": 3,
"/": 3,
"+": 2,
"-": 2,
"(": 1,
")": 1
}
if not self.parseChecker(inOrdErexpr):
raise ValueError
opStack = Stack()
postOrderList = list()
exprList = inOrdErexpr.split()
for ch in exprList:
if ch.isdigit():
postOrderList.append(ch)
elif ch == "(":
opStack.push(ch)
elif ch == ")":
topOper = opStack.pop()
while topOper != "(":
postOrderList.append(topOper)
topOper = opStack.pop()
else:
# 比较运算符优先级,如果栈中运算符的优先级>当前运算符, 追加至转换列表中
while (not opStack.isEmpty()) and (prec[opStack.peek()] > prec[ch]):
postOrderList.append(opStack.pop())
opStack.push(ch)
# 将栈中的运算符追加至转换列表中
while not opStack.isEmpty():
postOrderList.append(opStack.pop())
return "".join(postOrderList)
def calculatePostOrderFormulas(self, postOrderformulas):
"""
计算后序表达式
"""
operaDict = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv
}
postStack = Stack()
postOrderList = list(postOrderformulas)
for ch in postOrderList:
if ch.isdigit():
postStack.push(eval(ch))
else:
opN1 = postStack.pop()
opN2 = postStack.pop()
postStack.push(operaDict[ch](opN2, opN1))
return postStack.pop()
def parseChecker(self, symbolStr):
"""
判断括号是否完全匹配
"""
symbolStr = self.extractBrackets(symbolStr)
s = Stack()
balanced = True
index = 0
while index < len(symbolStr) and balanced:
symbol = symbolStr[index]
if symbol in "{[(":
s.push(symbol)
elif s.isEmpty():
balanced = False
else:
topSym = s.pop()
if self.matches(topSym, symbol):
balanced = False
index += 1
if balanced and s.isEmpty():
return True
else:
return False
def extractBrackets(self, formulas):
regex = re.compile(r'[{\[()\]}]')
return "".join(regex.findall(formulas))
def matches(self, open, close):
opens = "{[("
closers = "}])"
return opens.index(opens) == closers.index(close)
if __name__ == "__main__":
formulas1 = "( 1 + 2 ) * 3"
formulas2 = "5 + 6 * 7"
postConversion = PostOrderConversion()
cFormulas1 = postConversion.conversionToPostOrder(formulas1)
cFormulas2 = postConversion.conversionToPostOrder(formulas2)
print("formulas1: %s | formulas1: %s" % (cFormulas1, cFormulas1))
print("formulas1: %s=" % formulas1, postConversion.calculatePostOrderFormulas(cFormulas1))
print("formulas2: %s=" % formulas2, postConversion.calculatePostOrderFormulas(cFormulas2))
计算结果
扫描二维码关注公众号,回复:
11575007 查看本文章
![](/qrcode.jpg)
formulas1: 12+3* | formulas1: 12+3*
formulas1: ( 1 + 2 ) * 3= 9
formulas2: 5 + 6 * 7= 47
创建栈
# -*- coding: utf-8 -*-
class Stack():
def __init__(self):
self.items = list()
def isEmpty(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[-1]
def size(self):
return len(self.items)
if __name__ == "__main__":
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
stack.push(4)
print(stack.items)
print(stack.peek())
print(stack.isEmpty())