视频教程:本视频介绍_哔哩哔哩_bilibili
一、栈
栈是一种线性结构,其基本特性就是先进后出(FILO)。
在python中通过列表list能实现栈:
###################################################################
# 栈:先进后出
# 有反转操作的流程,用栈比较合适
###################################################################
# 创建栈类,栈有push、pop、peek、size、isEmpty五种属性
class Stack:
def __init__(self):
self.items = [] # 初始化空栈
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]
# return self.items[len(self.items)-1]
def size(self): # 栈长度
return len(self.items)
def __repr__(self): # 打印输出
return self.items
最简单实现栈的代码:
# 极简栈
class simple_Stack(list):
def push(self, item):
self.append(item)
def peek(self):
return self[-1]
def isEmpty(self):
return self == []
def size(self):
return len(self)
栈的应用实例:
1、进行括号匹配:
# 进行括号匹配,这部分代码只涉及小括号的匹配
def parChecker(symbolString): # 仅匹配圆括号
s = Stack()
balanced = True # 是否匹配标志
index = 0
while index < len(symbolString) and balanced: # 没有检索完且匹配
symbol = symbolString[index] # 获得字符
if symbol == '(': # 左括号入栈
s.push(symbol)
else: # 有括号,进行匹配
if s.isEmpty(): # 栈已经空了,说明右括号是多的,不匹配
balanced = False
else: # 栈不空,最后一个左括号出栈
s.pop()
index = index + 1 # 搜索下一个字符
if balanced and s.isEmpty(): # 完全匹配
return True
else: # 不完全匹配,左括号是多的
return False
print(parChecker('((()()))'))
print(parChecker('(()'))
支持小括号、中括号、大括号的匹配:
def match(chr1, chr2):
opens = ["{", "[", "("]
closers = ['}', ']', ")"]
return opens.index(chr1) == closers.index(chr2)
def allparChecker(symbolString): # 匹配多重括号
s = Stack()
balanced = True # 是否匹配标志
index = 0
while index < len(symbolString) and balanced: # 没有检索完且匹配
symbol = symbolString[index] # 获得字符
if symbol in '{[(': # 左括号入栈
s.push(symbol)
else: # 有括号,进行匹配
if s.isEmpty(): # 栈已经空了,说明右括号是多的,不匹配
balanced = False
else: # 栈不空,最后一个左括号出栈
if match(s.peek(), symbol):
s.pop()
else:
balanced = False
index = index + 1 # 搜索下一个字符
if balanced and s.isEmpty(): # 完全匹配
return True
else: # 不完全匹配,左括号是多的
return False
print(allparChecker('({})'))
print(allparChecker('({}])'))
print(allparChecker('([{}])'))
2、十进制转换成n进制,采用取余数的方法,python实现代码如下:
# 十进制转为n进制
def divideBynum(decNumber, base=2):
digits = '0123456789ABCDEF' # 设置进制的表示符表
remstack = Stack()
while decNumber > 0: # 除数仍然大于0,继续转化为二进制
rem = decNumber % base # 取余数
remstack.push(rem) # 余数进栈
decNumber = decNumber // base # 除二取整
binString = ''
while not remstack.isEmpty(): # 余数栈不为空
binString = binString + digits[remstack.pop()] # 取出最后一个余数
return binString
print(divideBynum(42, 16))
3、中缀表达式转后缀表达式。
中缀表达式指操作符在两个操作数之间,如:A+B;后缀表达式指操作数在两个操作符之后,如:AB+。它们表达同样的意思,即A和B相加。前缀表达式同理。
对于计算机而言,要处理中缀表达式会比较麻烦,而处理后缀表达式则比较简单,所以在处理表达式之前,需要先把输入的中缀表达式转换成后缀表达式,下面为python实现的代码:
# 中缀表达式转后缀表达式
def infixToPostfix(infixespr):
prec = {} # 操作符优先级字典
prec['*'] = 3
prec['/'] = 3
prec['+'] = 2
prec['-'] = 2
prec['('] = 1
opStack = Stack() # 操作符栈
postfixList = [] # 操作数list
tokenList = infixespr.split()
for token in tokenList: # 取出字符
if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token not in prec.keys(): # 对操作数进行
postfixList.append(token) # 把操作数记录于操作数list中,因为后缀表达式中操作数在操作符前面,且顺序不会发生改变
elif token == '(': # 遇到左括号
opStack.push(token) # 操作符记录左括号
elif token == ')': # 遇到右括号,开始输出操作符
topToken = opStack.pop() # 输出顶端操作符
while topToken != '(': # 括号输出还没结束
postfixList.append(topToken) # 记录输出
topToken = opStack.pop() # 继续输出栈顶
else: # 遇到非括号操作符
while (not opStack.isEmpty()) and (prec[opStack.peek()] >= prec[token]): # 操作符栈不为空 且 当前操作符优先级小于等于栈顶操作符优先级
postfixList.append(opStack.pop()) # 输出栈顶操作符优先级,即上一步应当参与的计算,如:先乘除后加减,同样优先级则从左往右计算。
opStack.push(token) # 直至栈空或者当前操作符优先级唯一最高,操作符入栈
while not opStack.isEmpty(): # 只要栈不是空的
postfixList.append(opStack.pop()) # 继续记录操作符
return ' '.join(postfixList) # 返回最终表达式
print(infixToPostfix('A + B / C * D / E'))
4、后缀表达式的计算问题。
从中缀表达式转换成后缀表达式后,再对表达式进行计算:
# 后缀表达式的计算
def doMath(token, operand1, operand2):
if token == '*':
result = operand1 * operand2
elif token == "/":
result = operand1 / operand2
elif token == "+":
result = operand1 + operand2
else:
result = operand1 - operand2
return result
def postfixEval(postfixExpr):
operandStack = Stack() # 记录操作数的栈
tokenList = postfixExpr.split() # 记录原始表达式
for token in tokenList: # 遍历表达式
if token.isdigit(): # 判断字符串是否为数字
operandStack.push(float(token)) # 若是数字,进操作数栈
else: # 若不为数字,进行数学运算
operand2 = operandStack.pop() # 先取出表达式后一个数
operand1 = operandStack.pop() # 再取出表达式前一个数
result = doMath(token, operand1, operand2) # 进行数学运算
operandStack.push(result) # 运算结果进栈
return operandStack.pop() # 遍历完表达式,也就计算完了所有的结果,最终栈里只剩下最后的计算结果,作为返回值
print(postfixEval(infixToPostfix('1 + 12 / 3 * 4 / 5')))