栈(stack):一个有次序的数据集,每个数据项仅从“栈顶(top)”一端加入到数据集中,从数据集中移除,栈具有后进先出(LIFO)的特性
需要实现的操作:
- Stack():创建一个空栈,不包含任何数据项
- push(item):将item加入栈顶,无返回值
- pop():将栈顶数据项移除,并返回,栈被修改
- peek():“窥视”栈顶数据项,返回栈顶数据项但不移除,栈不被修改
- isEmpty():返回栈是否为空栈
- size():返回栈中有多少个数据项
python实现:
class MyStack:
def __init__(self):
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 isEmpty(self):
return self.items == []
def size(self):
return len(self.items)
测试:
from stack import MyStack #我的MyStack类保存在了一个 stack.py 文件中
s = MyStack()
print(s.isEmpty())
s.push('hello')
print(s.peek())
s.push(True)
s.push(6.66666)
print(s.pop())
print(s.peek())
print(s.size())
终端输出:
True
hello
6.66666
True
2
应用:中缀表达式 转 后缀表达式
中缀表达式:A + B *C + D
全括号中缀表达式:((A + (B * C)) + D)
后缀表达式:ABC*+D+
前缀表达式:++A*BCD
中缀 —> 全括号 :
- 相当于在正常运算时,每一个步骤都加上括号
全括号 —> 后缀:
- 从最里层括号开始运算
- 如上例,最里层(B * C),用 * 代替右括号,然后去掉左括号得到 BC*
- 下一层(A + BC*),+ 代替右括号,去掉左括号,得到 ABC*+
- 去掉最后一层括号得到 ABC*+D+
全括号中缀表达式 转 前缀表达式:操作符代替左括号
中缀转后缀算法分析:
- 计算机从左至右扫描中缀表达式,在扫描到第二个操作数之前,要把操作符先保存起来(使用栈)
- 被存储起来的运算符由于运算优先级的关系,可能要反转输出次序,如 A + B * C ,+ 先被扫描,但是优先级低于 * ,因此要等待 * 先输出,然后在输出 +
- 中缀表达式中可能存在括号,如(A + B)* C,括号中 + 的优先级高于外部的 * ,所以遇见左括号 ‘(’,则标记后面出现的内容全部提升优先级,一旦遇见右括号 ‘)’,则将括号内剩余的操作符输出
算法流程:
- 定义一个空栈(opStack)保存操作符
- 定义一个空列表(postfixList)接收后缀表达式
- 使用 str.split() 将中缀表达式拆分成单个字符(token)
- 逐一判断字符,是操作数就直接添加到 postfixList 中,是操作符则判断后在决定是保存进栈或是输出到 postfixList
- 扫描完成后将栈中剩余的操作符输出到 postfixList 中
- 使用 str.jion() 将 postfixList 中的元素组装成后缀表达式
from stack import MyStack
def infixToPostfix(infixexpretion):
#定义操作符的优先级
precedence = {}
precedence['*'] = 3
precedence['/'] = 3
precedence['+'] = 2
precedence['-'] = 2
precedence['('] = 1
opStack = MyStack() #定义一个空栈保存操作符
postfixList = [] #定义一个空列表接收后缀表达式
tokenList = infixexpretion.split() #将输入的表达式拆分成单个字符
#逐一处理字符
for token in tokenList:
if token in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' or token in '0123456789':
postfixList.append(token)
elif token == '(':
opStack.push(token)
elif token ==')':
topToken = opStack.pop()
while topToken != '(':
postfixList.append(topToken)
topToken = opStack.pop()
#处理运算优先级问题
else:
while (not opStack.isEmpty()) and precedence[opStack.peek()] > precedence[token]:
postfixList.append(opStack.pop())
opStack.push(token)
#扫描完成后处理剩余操作符
while not opStack.isEmpty():
postfixList.append(opStack.pop())
return ' '.join(postfixList)
if __name__ == "__main__":
#由于split()默认以空白符进行分割,要求输入的中缀表达式以空格分隔
print(infixToPostfix('A + B * C'))
print(infixToPostfix('( A + B ) * C - ( D - E ) * ( F + G )'))
终端输出:
A B C * +
A B + C * D E - F G + * -
————
8.15 更新
对于上述代码,运行程序输入中缀表达式时需要用空格分隔每个字符,这一点不是很方便,可以将
tokenList = infixexpretion.split()
修改为
tokenList = list(infixexpretion)
即不需要使用 split 函数拆分表达式,直接将 str 类型转换为 list 类型,这样在输入中缀表达式时不必在用空格分隔。