栈是一种操作受限的线性表,只允许在一端插入或删除数据,后进先出,先进后出,就是典型的栈结构。
栈主要包含2个操作,入栈和出栈,也就是在栈顶插入或删除一个元素。
实现一个基于数组的顺序栈:
class Stack:
def __init__(self, cap=64):
self.L = []
self.cap = cap
self.cnt = 0
def push(self, data):
if self.cnt == self.cap:
return False
self.L.append(data)
self.cnt += 1
return True
def pop(self):
if self.cnt == 0:
return None
v = self.L.pop()
self.cnt -= 1
return v
栈在表达式求值中的应用
将表达式简化为只包含加、减、乘、除四则运算,例如:3 + 2 * 4 - 1,人脑可以迅速得出答案,但是对于计算机来说,理解这个表达式就是一件很难的事。
我们可以使用2个栈,一个保存数据,另一个保存操作符,从左向右遍历表达式,当遇到数字就直接压入数据栈,遇到操作符时就与操作符栈顶元素比较:
- 如果比栈顶操作符优先级高,直接将当前运算符入栈
- 如果比栈顶元素优先级低或者相同,则从操作符栈取出元素,再从数据栈取出2个元素进行计算,结果保存到数据栈,然后继续比较
用代码实现如下:
class UnsupportExpressionError(Exception):
pass
class UnsupportOperationError(Exception):
pass
class SimpleCalculator:
_priority = {
'+': 10, '-': 10,
'*': 20, '/': 20,
}
_digits = {
'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,
'5': 5, '6': 6, '7': 7, '8': 8, '9': 9
}
def __init__(self, expression):
self.symbol_stack = Stack()
self.number_stack = Stack()
self.expression = expression
self._result = self.get_result()
@property
def result(self):
return self._result
def get_result(self):
decimal = 0
for x in self.expression:
v = x.strip()
if not v:
continue
if v in self._priority:
self.number_stack.push(decimal)
decimal = 0
self.cmp_and_calc(v)
self.symbol_stack.push(v)
elif v in self._digits:
decimal = decimal * 10 + self._digits[v]
else:
raise UnsupportExpressionError(f'unsupport operation: "{v}" in expression: {self.expression}')
self.number_stack.push(decimal)
operation = self.symbol_stack.pop()
while operation:
ret = self._calc_helper(operation)
self.number_stack.push(ret)
operation = self.symbol_stack.pop()
ret = self.number_stack.pop()
return ret
def cmp_and_calc(self, operation):
symbol = self.symbol_stack.pop()
if symbol is None:
return
if self._priority[operation] > self._priority[symbol]:
self.symbol_stack.push(symbol)
else:
ret = self._calc_helper(symbol)
self.number_stack.push(ret)
self.cmp_and_calc(operation)
def _calc_helper(self, operation):
b = self.number_stack.pop()
a = self.number_stack.pop()
if a is None:
return b
if operation == '+':
return a + b
elif operation == '-':
return a - b
elif operation == '*':
return a * b
elif operation == '/':
return a / b
else:
raise UnsupportOperationError(f'unsupport operation: {operation}')
def main():
s = ''
while not s or not s.strip():
s = input('please enter an expression: ')
c = SimpleCalculator(s)
print(c.result)
带括号的表达式求值
同理可以使用一个栈保存表达式,当遇到右括号时,将该括号对里面的表达式使用上面的 SimpleCalculator 计算,得出的结果再压入栈,最后得到的表达式就是一个不含括号的表达式了。
例如表达式:2*(6/(1+2)) 计算过程:
- 将 '2*(6/(1+2' 依次入栈
- 遇到 ')' ,不断从栈中取出数据,直到有匹配的左括号
- 然后计算 '1+2' 将结果 3 入栈
- 遇到 ')' ,计算 '6/3' 将结果 2.0 入栈
- 最再计算表达式 2*2.0 得出最终结果: 4.0
SimpleCalculator 不支持小数,改写 get_result 函数:
def get_result(self):
decimal = 0
has_dot = False
factor = 0
for x in self.expression:
v = x.strip()
if not v:
continue
if v == '.':
has_dot = True
factor = 0.1
elif v in self._priority:
self.number_stack.push(decimal)
decimal = 0
has_dot = False
factor = 0
self.cmp_and_calc(v)
self.symbol_stack.push(v)
elif v in self._digits:
if not has_dot:
decimal = decimal * 10 + self._digits[v]
else:
decimal = decimal + self._digits[v] * factor
factor = factor * 0.1
else:
raise UnsupportExpressionError(f'unsupport operation: "{v}" in expression: {self.expression}')
self.number_stack.push(decimal)
operation = self.symbol_stack.pop()
while operation:
ret = self._calc_helper(operation)
self.number_stack.push(ret)
operation = self.symbol_stack.pop()
ret = self.number_stack.pop()
return ret
带括号的表达式求解:
class BracketsCalculator:
_match_pair = {
')': '(',
']': '[',
'}': '{',
}
def __init__(self, expression):
self.exp_stack = Stack()
self.expression = expression
self._result = self.get_result()
@property
def result(self):
return self._result
def get_result(self):
exp = ''
for x in self.expression:
v = x.strip()
if not v:
continue
if v in (')', ']', '}'):
val = self.exp_stack.pop()
while val != self._match_pair[v]:
exp = f'{val}{exp}'
val = self.exp_stack.pop()
ret = SimpleCalculator(exp).result
self.exp_stack.push(ret)
exp = ''
else:
self.exp_stack.push(v)
val = self.exp_stack.pop()
while val is not None:
exp = f'{val}{exp}'
val = self.exp_stack.pop()
return SimpleCalculator(exp).result