python-栈的实现
栈(Stack)的定义:只允许在一端进行插入或者删除操作的线性表。
栈顶(Top):线性表允许插入和删除的那一端。
栈底(Bottom):固定的,不允许进行插入和删除的那一端。
空栈:不含任何元素的空表。
这里借用一个百度百科的图片展示入栈和出栈的过程:
栈是后入先出(LIFO,last-in-first-out)的数据结构,假设栈中原始数据为(2,7,1)
该图展示了8和2依次入栈(Push())
以及(2,8,1)依次出栈(Pop())的过程。
栈的基本操作:
IniStack():初始化一个空栈
isempty():判空
isfull():判满
Push():若栈未满,则入栈
Pop():若栈非空,则出栈
GetTop():获取栈顶元素
顺序栈的实现:
# 后进先出
class myStack():
def __init__(self,size):
self.size=size #栈的大小
self.stack=[] #定义一个空栈
self.top=-1 #指示栈的存储情况,初始为-1,表示空栈,每入栈一个元素,top增加1,每出栈一个元素,top减少1
def push(self, x): # 入栈之前检查栈是否已满
if self.isfull():
print("stack is full")
return False
else:
self.stack.append(x)
self.top = self.top + 1
return True
def pop(self):# 出栈之前检查栈是否为空
if self.isempty():
print("stack is empty")
return False
else:
self.top = self.top - 1
self.stack.pop()
return True
def gettop(self):
if self.top!=-1:
return self.stack[self.top]
def isfull(self):
return self.top+1 == self.size
def isempty(self):
return self.top == '-1'
def showStack(self):
print(self.stack)
s=myStack(10)
for i in range(10):
s.push(i)
s.showStack()
print(s.gettop())
s.push("100")
for i in range(6):
s.pop()
s.showStack()
输出为:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
9
stack is full
[0, 1, 2, 3]
需要注意的地方:
1)入栈的时候:元素先入栈,top再增1;出栈时:top先减1,元素后出栈
2)top初值为-1表示空栈,top+1==size表示满栈
共享栈:
利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一维空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸。
两个栈的栈顶指针都指向栈顶元素,top0=-1时0号栈为空,top1=maxSize时1号栈为空,仅当两个栈顶相邻时栈满:top1-top0==1
入栈时,top0先加1再赋值;top1先减1再赋值
class SharedStack:
def __init__(self, size):
self.size = size
self.array = [None] * size # 初始化共享空间
self.top1 = -1 # 第一个栈的栈顶位置
self.top2 = size # 第二个栈的栈顶位置
def push1(self, value):
if self.top1 < self.top2 - 1: # 检查是否还有空间可用
self.top1 += 1
self.array[self.top1] = value
else:
print("Stack 1 overflow")
def push2(self, value):
if self.top1 < self.top2 - 1: # 检查是否还有空间可用
self.top2 -= 1
self.array[self.top2] = value
else:
print("Stack 2 overflow")
def pop1(self):
if self.top1 >= 0: # 检查第一个栈是否为空
value = self.array[self.top1]
self.top1 -= 1
return value
else:
print("Stack 1 underflow")
return None
def pop2(self):
if self.top2 < self.size: # 检查第二个栈是否为空
value = self.array[self.top2]
self.top2 += 1
return value
else:
print("Stack 2 underflow")
return None
# 创建一个大小为10的共享栈
shared_stack = SharedStack(10)
# 向第一个栈压入数据
shared_stack.push1(1)
shared_stack.push1(2)
shared_stack.push1(3)
# 向第二个栈压入数据
shared_stack.push2(4)
shared_stack.push2(5)
# 从第一个栈弹出数据
print(shared_stack.pop1()) # 输出:3
# 从第二个栈弹出数据
print(shared_stack.pop2()) # 输出:5
首先,创建一个共享栈的类 SharedStack,在初始化方法中,指定了共享空间的大小,并创建了一个列表 array来存储共享空间的数据。 通过两个指针 top1 和 top2 分别表示两个栈的栈顶位置。初始时,第一个栈的栈顶 top1 设置为-1,第二个栈的栈顶 top2 设置为共享空间的大小。 实现 push1 和 push2 方法来向两个栈中压入数据。在压入数据时,我们需要检查栈是否已满,即 top1 是否小于 top2 - 1,如果满了则输出溢出信息。 实现pop1 和 pop2 方法来从两个栈中弹出数据。在弹出数据时,我们需要检查栈是否为空,即 top1 是否大于等于 0 或者 top2是否小于共享空间的大小,如果为空则输出下溢信息。
最后,我们创建一个大小为10的共享栈实例,向两个栈分别压入数据,然后从两个栈分别弹出数据,以验证共享栈的功能。
链栈:
采用链式存储结构的栈,不存在栈满溢出的情况,便于节点的插入和删除,通常用单链表实现,并规定所有的操作都是在表头进行的。
下图的链栈没有头结点,Lhead指向栈顶元素。
class ListNode:
def __init__(self, value=0, next=None):
self.value = value
self.next = next
class LinkedStack:
def __init__(self):
self.top = None # 栈顶指针,初始时指向空
def push(self, value):
new_node = ListNode(value) # 创建一个新节点
new_node.next = self.top # 将新节点的next指针指向当前栈顶节点
self.top = new_node # 更新栈顶指针,指向新节点
def pop(self):
if self.top is None:
raise Exception("Stack is empty") # 如果栈为空,则抛出异常
value = self.top.value # 获取栈顶节点的值
self.top = self.top.next # 将栈顶指针指向下一个节点
return value # 返回弹出的值
def is_empty(self):
return self.top is None # 如果栈顶指针为空,则栈为空
def peek(self):
if self.top is None:
raise Exception("Stack is empty") # 如果栈为空,则抛出异常
return self.top.value # 返回栈顶节点的值
# 创建一个链栈实例
stack = LinkedStack()
# 将元素依次压入栈中
stack.push(1)
stack.push(2)
stack.push(3)
# 弹出栈顶元素并打印
print("弹出栈顶元素:", stack.pop())
# 打印当前栈顶元素
print("当前栈顶元素:", stack.peek())
# 判断栈是否为空
print("栈是否为空:", stack.is_empty())
定义一个 ListNode 类来表示链栈的节点,每个节点包含一个 value 值和一个 next 指针指向下一个节点。 定义一个 LinkedStack 类来实现链栈。其中 top 指针指向栈顶节点,初始时为空。 push方法用于向栈中压入元素,每次压入元素时,创建一个新节点,将新节点的 next 指针指向当前栈顶节点,然后更新 top 指针,使其指向新节点。
pop 方法用于弹出栈顶元素,首先检查栈是否为空,然后获取栈顶节点的值,并将 top 指针指向下一个节点,最后返回弹出的值。
is_empty 方法用于判断栈是否为空,只需判断 top 指针是否为空即可。 peek 方法用于获取栈顶元素的值,首先检查栈是否为空,然后返回栈顶节点的值。
通过以上实现,我们完成了链栈的基本操作,并且可以对链栈进行压栈、弹栈、查看栈顶元素和判断栈是否为空等操作。