四种线性结构 之栈Stack
栈Stack
队列Queue
双端队列Deque
列表List
这些线性结构是应用最广泛的数据结构,它们出现在各种算法中,解决各种重要的问题
栈Stack
一种有次序的数据项集合,在栈中,数据项的加入和移除都仅发生在同一端,这一段叫做栈的“顶Top”,另一端叫栈的“底base”
距离栈底越近的数据项,留在栈中的时间就越长,而最新加入栈的数据项会被最先移除,这种次序通常称为“先进后出LIFO”,即Last in First out。这是一种基于数据项保存时间的次序,时间越短的离栈顶越近,而时间越长的离栈底越近
栈的特性:反转次序
这种访问次序反转的特性,举例如:浏览器的“后退back”按钮,最先back的是最近访问的网页,Word里的undo按钮最先撤销的是最后执行的操作
在Python中抽象数据类型栈有如下操作:
Stack(): 创建一个空栈,不包含任何数据项
push(item): 将item加入栈顶,无返回值
pop(): 将栈顶数据移除,并返回,栈被修改
peek(): “窥视”栈顶数据项,返回栈顶的数据项,但不移除,栈不被修改
isEMpty(): 返回栈是否为空栈
size(): 返回栈中有多少个数据项
用Python实现ADT Stack
由于Stack是一个数据集,所以可以采用Python的原生数据集(List和dict)来实现。我们选用最常用的数据集List来实现
可以将List的任意一段(index=0或者-1)设置为栈顶
我们选用List的末端(index=-1)作为栈顶,这样栈的操作就可以通过对List的append和pop来实现
栈的应用1:简单括号匹配
构造括号匹配识别算法:从左到右扫描括号串,最新打开的左括号,应该匹配最先遇到的右括号,这样第一个左括号(最早打开的),就应该匹配最后一个右括号(最后遇到的),这种次序反转的识别,正好符合栈的特性
暴力判断:
from pythonds.basic.stack import Stack
def parChecker1(symbolString):
s = Stack()
balanced = True
index = 0
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if symbol == "(" or symbol == "[" or symbol == "{" :
s.push(symbol)
elif symbol == ")":
if s.isEmpty() or s.peek() == "[" or s.peek() == "{":
balanced = False
else:
s.pop()
elif symbol == "]":
if s.isEmpty() or s.peek() == "(" or s.peek() == "{":
balanced = False
else:
s.pop()
elif symbol == "}":
if s.isEmpty() or s.peek() == "(" or s.peek() == "[":
balanced = False
else:
s.pop()
index = index + 1
if balanced and s.isEmpty():
return True
else:
return False
匹配判断:
def parChecker2(symbolString):
s = Stack()
balanced = True
index = 0
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if symbol in "([{" :
s.push(symbol)
elif symbol in ")]}":
if s.isEmpty() :
balanced = False
else:
top = s.pop()
if not matches(top,symbol):
balanced = False
index = index + 1
if balanced and s.isEmpty():
return True
else:
return False
def matches(open, close):
opens = "([{"
closes = ")]}"
return opens.index(open) == closes.index(close)
print(parChecker2("(5*(4+3){[]}())"))
检查一下输出结果正确
栈的应用2:十进制转换二进制
利用除以2得到一个十进制数的二进制表达形式,在除以2的过程中,得到的余数是从低位到高位的次序,而输出则是从高到低,所以需要一个次序反转,因此需要用到栈。
def matches(open, close):
opens = "([{"
closes = ")]}"
return opens.index(open) == closes.index(close)