栈与队列理论基础
队列queue是先进先出(FIFO),而栈stack是先进后出 / 后进先出 (LIFO)。由于使用的语言是Python,因此主要用列表List来解释栈stack。
用List来实现栈,需要分清楚栈的头尾。先进入栈的数据如同装进瓶子的石头,会被积压在底部;而后进入栈的数据会在倒瓶子的时候必先进入的数据优先被取出来。因此,队列的头部实际是栈的底部,它会储存最后被导出的数据;而队列的尾部是栈的顶部,接受新的装入栈的数据。装入栈的时候我们可以利用列表的append()往队列的末尾加入新数据,而取出栈顶数据的代码,会根据是用栈实现队列,还是队列实现栈,而有所差异。
232.用栈实现队列
Leetcode 232 原题链接
本题要求时实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾。队列的尾部就是指栈顶,也就是要将元素x作为最后一个压入栈的元素。
int pop()
从队列的开头移除并返回元素。队列的开头就是指栈底,指栈的最下面的元素,也就是最先被压入栈的元素。
int peek()
返回队列开头的元素。
boolean empty()
如果队列为空,返回 true ;否则,返回 false
输入栈和输出栈
在push数据的时候,只要数据放进输入栈就好;但在pop的时候,操作就复杂一些,需要两个栈,一个是储存数据的输入栈,一个则是完成弹出操作的输出栈:输出栈如果为空,就把进栈数据全部导入进来,再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
输入栈和输出栈的方向是相反的。输入栈 stack_in 用于存储原始的元素顺序,而输出栈 stack_out 用于存储元素的逆序。
当需要从队列中弹出元素时,先检查输出栈是否为空。如果输出栈不为空,则直接从输出栈的底部弹出元素,这样可以保证先入先出的顺序。如果输出栈为空,则将输入栈中的元素逐个弹出,并依次推入输出栈,以实现先入先出的效果。
因此,输入栈和输出栈在逻辑上是相反的,输入栈存储的是原始的元素顺序,而输出栈存储的是元素的逆序。此时,要注意,下图中的输出栈实际方向为从右往左,和左边的输入栈方向已经相反了。
class MyQueue:
def __init__(self):
self.stack_in = []
self.stack_out = []
def push(self, x: int) -> None:
self.stack_in.append(x)
def pop(self) -> int:
if self.empty():
return None
if self.stack_out:
return self.stack_out.pop()
# 这里的pop()不同于我们命名的function,pop()是移除并返回列表中的最后一个元素
else:
for i in range(len(self.stack_in)):
self.stack_out.append(self.stack_in.pop())
return self.stack_out.pop()
def peek(self) -> int:
# 要的就是pop(self)返回的开头元素
ans=self.pop() # 这是上面命名的pop()
self.stack_out.append(ans) # 运行pop(self)把该元素从输出栈里移除了,要重新加进去
return ans
def empty(self) -> bool:
return not (self.stack_in or self.stack_out)
# 只要in或者out有元素,说明队列不为空
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
225. 用队列实现栈
Leetcode 225 原题链接
本题要求实现 MyStack 类:
void push(int x)
将元素 x 压入栈顶。也就是在队列的尾部插入新元素。
int pop()
移除并返回栈顶元素。也就是移除并返回队列尾部元素。
int top()
返回栈顶元素。
boolean empty()
如果栈是空的,返回 true ;否则,返回 false
不同于用栈实现队列的时候需要构建输入栈和输出栈,用队列实现栈只需要一个队列即可解决。
class MyStack:
def __init__(self):
self.stack=[]
def push(self, x: int) -> None:
# 压入栈顶等于是放在最上面,相等于放到列表的后面
self.stack.append(x)
def pop(self) -> int:
ans=self.top() # 先找到栈顶元素,也就是列表末尾元素
self.stack.pop() # 移除该元素
return ans
def top(self) -> int:
return self.stack[-1] # 返回栈顶元素,也就是列表末尾元素
def empty(self) -> bool:
# return True if not self.stack else False
return self.stack==[]
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()