栈是一种运算会受到相关限制的数据结构,简单来说,栈就是一种数据的存储方式。在这种数据的存储方式中进行存入数据或者读取数据的操作时,会受到相关规则的限制。
栈这种数据结构具有以下几个特点:
- 栈相当于一端开口、一端封闭的容器;
- 数据可存储在栈里面,把数据移动到栈里面的过程叫作进栈,也称为压栈、入栈;
- 栈只能对其栈顶的数据进行操作;
- 栈是一种先进后出的数据结构
栈的一端是开口的,一端是封闭的。开口的这一端可以进数据与出数据,闭合的这一端不能进数据,也不能出数据。闭合的这一端的位置称为栈底。在最开始的时候,如果栈里面没有数据,栈顶与栈底是重合的。在进入数据后,栈顶会逐渐往上移动,而栈底的位置始终处于闭合端所在的位置。
为了更好的理解栈的存储结构,不妨尝试着将栈的存储结构抽象一下,形成 “栈的普遍存储结构图示”,如果把栈底位置的下标标注为 -1,那么数据1所在的位置下标为0,数据2所在的位置下标为1,以此类推,数据 n 所在的位置下标为 n-1。其实数据 1 ~ 数据 n 的存储的最基本形式就是列表,只不过这种列表里面的数据操作是受限制的,只能对列表中的最后一个元素进行操作。
在通过Python代码进行栈的基本应用时,可以把栈的基本形态看成列表,只不过需要对这种列表的数据操作进行限制,比如只能在表的一端进行数据的插入和删除等。
栈的完整代码实现:
#栈的实现
class Stack():
def __init__(self,size): #在类中建立一个初始化方法
self.data=["null" for i in range(0,size)] #生成指定长度(size)的列表,并且该列表中的各元素数据初始时都是为null
self.size=size #对栈的大小进行初始化
self.top=-1 #实现栈顶位置top的初始化
def push(self,content): #入栈
if self.Full():
print("栈已满,不允许入栈!")
else:
self.top=self.top+1
self.data[self.top]=content #将新元素放到当前的栈顶位置所指向的存储单元
def out(self): #出栈
if self.Empty():
print("栈已空,不允许出栈!")
else:
print(self.data[self.top])
self.data[self.top]="null" #使用赋一个特定值(如"null")的方式模拟清空操作
self.top=self.top-1
def Full(self): #判断是否栈满
if self.top==self.size-1: #用size表示栈的大小,则栈满时栈顶的下标为size-1
return True
else:
return False
def Empty(self): #判断是否栈空
if self.top==-1: #当栈顶为-1时判断该栈为空
return True
else:
return False
在PyCharm中,鼠标右击选择 “Run File in Console” 进入Python Shell
#创建一个大小为4的栈,将数据依次进栈
>>> s=Stack(4)
>>> s.push("zcoder")
>>> s.push("App")
>>> s.push("Hhhhh")
>>> s.push("Pink")
#此时栈内已有四个数据,无法再进栈
>>> s.push("OK")
栈已满,不允许入栈!
>>> s.out()
Pink
>>> s.out()
Hhhhh
>>> s.out()
App
>>> s.out()
zcoder
>>> s.out()
栈已空,不允许出栈!
#随时可以使用Empty()与Full()方法分别判断是否栈空或栈满
>>> s.Empty()
True
>>> s.Full()
False
那么栈这种数据结构的应用场景是什么呢?
其实凡是先进后出的业务逻辑执行流程都可以使用到这种数据结构。不妨假设这样的情景:
现在有4个应用程序A、B、C、D,系统同时最多只能执行一个应用程序,具体执行哪个应用程序由使用者进行选择,此时希望,如果前一个应用程序已经执行,而使用者又开启了一个新的应用程序,系统优化执行新开启的程序,而原程序进入挂起状态,当新开启的程序执行完毕之后,再依次激活原程序进行执行。
这里程序的执行方案是:新开启的程序优先于已开启的程序执行。满足先进后出的规律。