一、一种实现
该种实现方式的性能更好
假设列表的尾部是栈的顶端。当栈增长时(即进行 push 操作), 新的元素会被添加到列表的尾部。pop 操作同样会修改这一端。
# main.py
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[len(self.items) - 1]
def size(self):
return len(self.items)
s = Stack()
print(s.isEmpty())
# 由于push函数只向栈中添加元素,而没有返回值,所以输出只有参数的地址
s.push(8.4)
print(s)
二、第二种实现
选择列表的头部作为栈的顶端。不过在这种情况下,便无法直接使 用 pop 方法和 append 方法,而必须要用 pop 方法和 insert 方法显式地访问下标为 0 的元素, 即列表中的第 1 个元素。
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.insert(0,item)
def pop(self):
return self.items.pop(0)
def peek(self):
return self.items[0]
def size(self):
return len(self.items)
三、匹配括号通过第一种实现
思路:由一个空栈开始,从左 往右依次处理括号。如果遇到左括号,便通过 push 操作将其加入栈中,以此表示稍后需要有一 个与之匹配的右括号。反之,如果遇到右括号,就调用 pop 操作。只要栈中的所有左括号都能 遇到与之匹配的右括号,那么整个括号串就是匹配的;如果栈中有任何一个左括号找不到与之匹 配的右括号,则括号串就是不匹配的。在处理完匹配的括号串之后,栈应该是空的。
#因为Stack类的定义在main.py,所以需要先导入
from main import Stack
def parChecker(symbolString):
s = Stack()
balanced = True
index = 0
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if symbol == "(":
s.push(symbol)
elif symbol == ")":
if s.isEmpty():
balanced = False
else:
s.pop()
index += 1
if balanced and s.isEmpty():
return True
else:
return False
四、匹配符号
思路:每一个左符号都将被压 入栈中,以待之后出现对应的右符号。唯一的区别在于,当出现右符号时,必须检测其类型是否 与栈顶的左符号类型相匹配。如果两个符号不匹配,那么整个符号串也就不匹配。同样,如果整 个符号串处理完成并且栈是空的,那么就说明所有符号正确匹配
#Stack类定义在main.py中,使用时需要导入
from main import Stack
def parChecker(symbolString):
s = Stack()
balanced = True
index = 0
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if symbol in "([{":
s.push(symbol)
elif symbol == ")":
if s.isEmpty():
balanced = False
else:
top = s.pop()
if not matches(top,symbol):
balanced = False
index += 1
if balanced and s.isEmpty():
return True
else:
return False
def matches(open,close):
opens = "([{"
closers = ")]}"
return opens.index(open) == closers.index[close]
五、进制转换
1.十进制转换成二进制
from main import Stack
def divideBy2(decNumber):
remstack = Stack()
while decNumber > 0:
rem = decNumber % 2
remstack.push(rem)
decNumber = decNumber // 2
binString = ""
while not remstack.isEmpty():
binString = binString + str(remstack.pop())#强制类型转换
return binString
print(divideBy2(32))
2.将十进制转换成任意进制
思路:
可以将 divideBy2 函数修改成接受一个十进制数以及希望转换的进制基数,“除以 2”则变 成“除以基数”;有时余数会超过10,需要定义一个字符串。
一种解决方法是添加一些字母字符到数字中。例如,十六进制使用 10 个数字以及前 6 个字 母来代表 16 位数字。
from main import Stack
def baseConverter(decNumber, base):
digits = "0123456789ABCDEF"
remstack = Stack()
while decNumber > 0:
rem = decNumber % base
remstack.push(rem)
decNumber = decNumber // base
newString = ""
while not remstack.isEmpty():
newString = newString + digits(remstack.pop())#字符拼接+digits(索引)
return newString
六中序表达式转换成后序表达式或者前序表达式
1.转换成后序表达式
思路:
(1) 创建用于保存运算符的空栈 opstack,以及一个用于保存结果的空列表。
(2) 使用字符串方法 split 将输入的中序表达式转换成一个列表。
(3) 从左往右扫描这个标记列表。
如果标记是操作数,将其添加到结果列表的末尾。
如果标记是左括号,将其压入 opstack 栈中。
如果标记是右括号,反复从 opstack 栈中移除元素,直到移除对应的左括号。将从栈中 取出的每一个运算符都添加到结果列表的末尾。
如果标记是运算符,将其压入 opstack 栈中。但是,在这之前,需要先从栈中取出优先 级更高或相同的运算符,并将它们添加到结果列表的末尾。
(4) 当处理完输入表达式以后,检查 opstack。将其中所有残留的运算符全部添加到结果列 表的末尾
from main import Stack
import string
def infixToPostfix(infixexper):
'''
中序表达式到后序表达式的转换
:param infixexper:
:return:
'''
# 给运算符定义优先级
prec = {}
prec["*"] = 3
prec["/"] = 3
prec["+"] = 2
prec["-"] = 2
prec["("] = 1
opStack = Stack() # 保存运算符的空栈
postfixList = [] # 保存结果的空列表
tokenList = infixexper.split()
for token in tokenList:
if token in string.ascii_uppercase:#什么意思
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 (prec[opStack.peek()] >= prec[token]):
postfixList.append(opStack.pop())
opStack.push(token)
while not opStack.isEmpty():
postfixList.append(opStack.pop())
return " ".join(postfixList)
infixexpr = "( A + B ) * ( C + D )"
print(infixToPostfix(infixexpr))
2.计算后序表达式
from main import Stack
def postfixEval(postfixExpr):
operandStack = Stack()
#从左向右遍历,如果为操作数则存入栈中,如果是运算符则取出栈中的两个运算数进行计算,结果存入栈中
tokenList = postfixExpr.split()#转化为列表
for token in tokenList:
#遍历到运算数
if token in "0123456789":
operandStack.push(int(token))#列表中的数据是字符型
#遍历到运算符
else:
operandr = operandStack.pop()#中序右运算数
operandl = operandStack.pop()#中序左运算数
result = domath(token,operandl,operandr)
operandStack.push(result)
return operandStack.pop()
def domath(token,operandl,operandr):
'''
定义运算
:param token: 运算符
:param operandl: 运算数
:param operandr: 运算数
:return: 运算结果
'''
if token == "*":
result = operandl*operandr
elif token == "/":
result = operandl / operandr
elif token == "+":
result = operandl + operandr
elif token == "-":
result = operandl - operandr
else:
#如果不是定义的,输出此,但是会多输出一个数字
print("the operator does not define the operation")#运算符未定义运算
return 0
return result
print(postfixEval("4 5 6 ^ +"))