1、概念
栈:后进先出的序列
队列:先进先出的序列
2、实现方式
2、1基本方法
1、创建
2、检查
3、压人
4、弹出
5、输出栈顶/队前元素
2、2栈
顺序表:采用尾端插入删除,实现入栈和出栈;
链表:采用前端插入和删除,实现入栈和出栈;
2、3栈的应用
方便的保存和取用信息
先进后出性质可以有特殊应用
eg: 括号匹配问题
eg:表达式的计算和转换
3、栈的实现
# 定义栈的异常
class stackUnderflow(ValueError):
pass
# 栈的顺序表实现:
class sstack:
def __init__(self):
self.elems = []
def is_empty(self):
return self.elems == []
def push(self, elem):
self.elems.append(elem)
def pop(self):
if self.elems == []:
raise stackUnderflow('in stack top!')
return self.elems.pop()
def top(self):
if self.elems == []:
raise stackUnderflow('in stack top!')
return self.elems[-1]
# 链表实现
class Node:
def __init__(self, elem, next_=None):
self.elem = elem
self.next_ = next_
class lstack:
def __init__(self):
self._head = None
def is_empty(self):
return self._head is None
def top(self):
if self._head is None:
raise stackUnderflow('in stack top!')
point = self._head
self._head = self._head.next_
return self._head.elem
def push(self, elem):
node = Node(elem)
if self._head is None:
self._head = node
else:
node.next_ = self._head
self._head = node
def pop(self):
if self._head is None:
raise stackUnderflow('in stack top!')
point = self._head
self._head = point.next_
return point.elem
# 测试
s1 = sstack()
for i in range(3):
s1.push(i)
try:
while (s1):
print(s1.pop(), end=' ')
print('\n')
except stackUnderflow as e:
print('\nstack has exported all elems!')
print('\n')
s2 = lstack()
for i in range(3):
s2.push(i)
try:
while (s2):
print(s2.pop(), end=' ')
print('\n')
except stackUnderflow as e:
print('\nstack has exported all elems!')
4、栈的应用
4.1栈的应用 括号的匹配 利用栈先进后出的特性来实现
# 从一个字符串中匹配出括号:首先括号集合要有;然后入栈的元素集合要有;括号匹配关系的集合要有;
def check_parens(text):
parens = '()[]{}'
open_parens = '([{'
opposite = {')': '(', ']': '[', '}': '{'}
# 开括号入栈
def parentheses(text):
i, text_len = 0, len(text)
while (True):
while i < text_len and text[i] not in parens:
i += 1
if i >= text_len:
return
yield text[i], i
i += 1
st = sstack() # 保存括号的栈 这里使用的顺序表形式的栈
for pr, i in parentheses(text):
if pr in open_parens:
st.push(pr)
elif st.pop() != opposite[pr]:
print('Unmatching is found at ', i, ' for ', pr)
return False
# else: 这次匹配成功什么也不做
print('All parentheses are correctly matched!')
return True
text = 'afa(aklfa{afjha[Lalk;fka;f]alkfaf[afalla]})'
check_parens(text)
4.2 表达式的计算、变换
4.2.1后缀表达式的计算
#################################################
# 表达式的计算变换过程:这里假定输入表达式是字符串,项之间是空格 ###########################################################
# 输入:字符串,项之间是空格
# 输出:计算结果
##########################################################
# 定义一个新的栈类来存储计算过程的临时数据
# 不足两个元素时计算失败,当栈中只有一个元素时结束计算。
class esstack(sstack):
def depth(self):
return len(self.elems)
# 将字符行分隔为项的表
def suffix_exp_evaluator(line):
return suf_exp_evaluator(line.split())
def suf_exp_evaluator(exp): # exp是一个列表
operators = '+-*/'
st = esstack()
for x in exp:
if x not in operators:
st.push(float(x))
continue
if st.depth() < 2:
raise SytaxError('short of operand(s).')
a = st.pop()
b = st.pop()
if x == '+':
c = b + a
elif x == '-':
c = b - a
elif x == '*':
c = b * a
elif x == '/':
if a == 0:
raise zeroDivisionError(str(b) + '/' + str(a))
c = b / a
else:
break
st.push(c)
if st.depth() == 1:
return st.pop()
raise SytaxError('Extra operand(s).')
# 使用suffix_exp_evaluator(line)完成 计算
# 定义一个交互式的驱动函数
def suffix_exp_caculator():
while True:
try:
line = input('Suffix Expression: ') # 有输入,所以是交互式的
#line = '1 2 + 3 4 + * 27 - 2 1 + /'
if line == 'end': return
res = suffix_exp_evaluator(line)
print(res)
except Exception as ex:
print('Error: ', type(ex), ex.args)
#测试
#text = '1 2 + 3 4 + * 27 - 2 1 + /'
suffix_exp_caculator()
4.2.2 中缀表达式转化为后缀表达式
#####################################################################
# 中缀表达式,转化为后缀表达式 #####################################################################
#定义生成器
def tokens(text):
text = text.split()
for i in text:
yield i
# 定义优先级和运算符集合
priority = {'(': 1, '+': 3, '-': 3, '*': 5, '/': 5} # 定义优先级
infix_operators = '+-*/()' # 定义运算符集合
def trans_infix_suffix(line):
st = sstack()
exp = []
# 对x的情况分析:
# 1、是数字;2、是左括号;3、是右括号;4、是运算符
# 数字就直接存入表中,左右括号决定着几个运算符的连续压人表中,
# 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
for x in tokens(line): # tokens 是一个带定义的生成器
if x not in infix_operators:
exp.append(x)
elif st.is_empty() or x == '(': # 左括号进栈
st.push(x)
elif x == ')': # 处理右括号分支
while not st.is_empty() and st.top() != '(':
exp.append(st.pop())
if st.is_empty(): # 没找到左括号,就不匹配
raise SyntaxError("Missing '('.")
st.pop() # 弹出左括号,右括号也不进栈
else:
while (not st.is_empty() and priority[st.top()] >= priority[x]):
exp.append(st.pop()) # 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
st.push(x)
while not st.is_empty():
if st.top() == '(':
raise SyntaxError("Extra '('.")
exp.append(st.pop())
return exp
# 测试函数
def test_trans_infix_suffix(text):
print(text)
print(trans_infix_suffix(text))
print('value: ', suf_exp_evaluator(trans_infix_suffix(text)))
#测试
text = '( ( 1 + 2 ) * ( 3 + 4 ) - 27 ) / ( 2 + 1 )'
#text = '( 1 + 2 ) * ( 3 + 4 ) - 27'
test_trans_infix_suffix(text)
4.2.3 中缀表达式的计算
#################################################
# 中缀表达式的求值
############################################################
#法1:利用后缀表达式计算来实现
#输入:以空白作为分隔
#输出:一个计算结果
`###################################################################################`
line = input('Infix Expression: ')
value = suf_exp_evaluator(trans_infix_suffix(line))
print(value)
#法2:直接计算
#运算符的优先级;括号作用;确定完成各运算的时机;做某个运算,找到正确的运算对象;这里是改进了中缀表达式转换为后缀表达式来实现的;将原本的运算符压人exp的数据栈,变为直接计算运算符,并将结果入栈
#定义生成器
def tokens(text):
text = text.split()
for i in text:
yield i
# 定义优先级和运算符集合
priority = {'(': 1, '+': 3, '-': 3, '*': 5, '/': 5} # 定义优先级
infix_operators = '+-*/()' # 定义运算符集合
def infix_exp_evaluator(line):
st = sstack()
exp = []
# 对x的情况分析:
# 1、是数字;2、是左括号;3、是右括号;4、是运算符
# 数字就直接存入表中,左右括号决定着几个运算符的连续压人表中,
# 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
for x in tokens(line): # tokens 是一个带定义的生成器
if x not in infix_operators:
exp.append(float(x))
elif st.is_empty() or x == '(': # 左括号进栈
st.push(x)
elif x == ')': # 处理右括号分支
while not st.is_empty() and st.top() != '(':
a = exp.pop()
b = exp.pop()
operator = st.pop()
c = caculate(b,a,operator)
exp.append(c)
if st.is_empty(): # 没找到左括号,就不匹配
raise SyntaxError("Missing '('.")
st.pop() # 弹出左括号,右括号也不进栈
else:
while (not st.is_empty() and priority[st.top()] >= priority[x]):
a = exp.pop()
b = exp.pop()
operator = st.pop()
c = caculate(b,a,operator) # 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
exp.append(c)
st.push(x)
while not st.is_empty():
if st.top() == '(':
raise SyntaxError("Extra '('.")
a = exp.pop()
b = exp.pop()
operator = st.pop()
c = caculate(b,a,operator)
exp.append(c)
return exp.pop()
def caculate(b,a,operator):
if operator == '+':
c = b + a
elif operator == '-':
c = b - a
elif operator == '*':
c = b * a
elif operator == '/':
if a == 0:
raise zeroDivisionError(str(b) + '/' + str(a))
c = b / a
else:
raise Exception(str(b) + operator + str(a))
return c
# 测试
line = '( ( 1 + 2 ) * ( 3 + 4 ) - 27 ) / ( 2 + 1 )'
infix_exp_evaluator(line)