欢迎关注微信公众号:简说Python
关注后回复:1024,可以领取精选编程学习电子书籍。
这两天和几个朋友组了个互相督促学习群,想着督促一下自己学习,也督促自己的原创输出,其实很多时候都是懒,真不是没有东西可以写了,这不,我在我的免费知识星球简说编程
里开了个新的标签日常编程问题
,后面我会把自己学习工作中遇到的一些问题和解决方法记录到里面,有些可以扩展的点,我会写到微信公众号里。
我定的目标是:
我简单写了个规则,大家说可以,然后,我们就开始吧,我习惯把该做的事情提前一天做(如果有时间的话)。
今天给大家分享的书籍《Python程序员面试算法宝典》第二章第三小节:如何翻转栈。
如果你是第一次看,也许,你可以看看本系列下面的文章:
Python数据结构:链表合集(12+7),复现几遍,包你学会
Smaller Python数据结构:自己动手实现栈
Smaller Python数据结构:自己动手实现队列
Smarter Python数据结构:如何翻转栈
Smarter Python数据结构:根据入栈序列来判断可能的出栈序列
Smarter Python数据结构:利用O(1)的时间复杂度求栈中最小元素
"""
目标:写一个程序,如何用两个栈模拟队列操作
Goal: Write a program, how to simulate queue operation with two stacks.
"""
老板: 今天考考你,怎么用两个栈来实现队列功能?
老表: 额~我想想。
首先我们之前已经写好了栈的基本操作,在b_1_implementation_stack.py
文件中,所以我们先导入这两个包。
from StackQueueHash.b_1_implementation_stack import LinkStack
另外我们要知道栈与队列的异同点,这样才知道该如何用栈实现队列或者用队列实现栈:
"""
Method One : 一个栈入队列,一个栈出队列
核心思想:入队列时,直接把元素压入入队列栈;出队列时,先把入队列栈元素转移到出队
列栈,获取出队列栈栈顶,即为出队列元素,将剩余元素从出队列栈再转移回入队列栈。
Method one: a stack in queue, a stack out queue
Core idea: when entering the queue, directly press the elements into
the queue stack; when leaving the queue, first transfer the elements
into the queue stack to get the top of the queue stack, that is, the
elements out of the queue, and then transfer the remaining elements
back to the queue stack.
"""
class MyQueue:
def __init__(self):
self.entry = LinkStack() # 入队列 栈
self.out = LinkStack() # 出队列 栈
# 不a栈的元素转移到b栈
def transfer_stack(self, a, b):
while not a.stack_is_empty(): # 将a栈元素倒出,存入b栈
top = a.get_stack_top() # 获取a栈栈顶
a.stack_pop() # 出栈
b.stack_push(top) # 栈顶压入b栈
# 入队列
def queue_push(self, x):
self.entry.stack_push(x) # 元素直接加入 入队列栈
# 出队列
def queue_pop(self):
# 出队列时,先把入队列栈转移到出队列栈
self.transfer_stack(self.entry, self.out)
# 获取出队列栈栈栈顶,即为出队列元素
out_element = self.out.get_stack_top()
self.out.stack_pop()
# 出栈,实现出队列操作
self.transfer_stack(self.out, self.entry)
# 将剩余元素从出队列栈再转移回入队列栈
return out_element # 返回出队列元素(队首)
老板: 嗯,小伙子不错,知道把有些共通的方法封装提炼出来(说的是栈数据倒入函数transfer_stack),那你还有办法可以把算法优化一下吗?你觉得你的代码里有没有不必要的步骤?
老表: 我想想~
"""
优化1:入队列时,先判断入队列栈是否为空,如果为空,则把出队列栈元素倒回
入队列栈,然后再入栈,如果不为空,说明元素全在入队列栈,则直接入栈即可;
出队列时,先判断出队列栈是否为空,如果为空,则将入队列栈元素倒入出队列栈,
然后取出栈顶即可,如果不为空,说明上次操作也是出队列,则直接获取出队列栈
栈顶即可。
这样做的好处是:如果连续操作是相同时,我们不需要来会把元素在入队列栈和出队
列栈倒来倒去。
Optimization 1: when entering the queue, first judge whether the
queue stack is empty. If it is empty, then pour the elements out
of the queue stack back into the queue stack, and then push the
elements in the queue stack. If it is not empty, it means that
all elements are in the queue stack, then directly push the elements
in the queue stack. When leaving the queue, first judge whether the
queue stack is empty. If it is empty, then pour the elements in the
queue stack into the queue stack, and then take out the top of the
stack , if it is not empty, it means that the last operation was also
out of the queue, then you can directly get out of the top of the queue
stack.
The advantage of this is that if the continuous operation is the same,
we don't need to pour the elements back and forth in the queue stack
and out of the queue stack.
"""
class MyQueue1:
def __init__(self):
self.entry = LinkStack() # 入队列 栈
self.out = LinkStack() # 出队列 栈
# 不a栈的元素转移到b栈
def transfer_stack(self, a, b):
while not a.stack_is_empty(): # 将a栈元素倒出,存入b栈
top = a.get_stack_top() # 获取a栈栈顶
a.stack_pop() # 出栈
b.stack_push(top) # 栈顶压入b栈
# 入队列
def queue_push(self, x):
if self.entry.stack_is_empty():
self.transfer_stack(self.out, self.entry)
# 把元素从出队列栈倒入入队列栈
self.entry.stack_push(x) # 元素入队列
else:
self.entry.stack_push(x) # 元素直接加入入队列栈,入队列
# 出队列
def queue_pop(self):
if self.out.stack_is_empty():
self.transfer_stack(self.entry, self.out)
# 把元素从入队列栈倒入出队列栈
out_element = self.out.get_stack_top()
# 获取栈顶,就是要出队列的元素
self.out.stack_pop()
# 出栈,完成出队列
return out_element # 返回出队列元素
老板: 嗯,小伙子不错,有点小灵敏哈~你觉得还能再优化吗?
老表: 可以,我想想~
"""
优化2:入队列时,直接入栈即可;
出队列时,先判断出队列栈是否为空,如果为空,则将入队列栈元素倒入出队列栈,
然后取出栈顶即可,如果不为空,说明上次操作也是出队列,则直接获取出队列栈
栈顶即可。
这样做的好处是:进一步简化代码,去掉不必要的转换。
Optimization 2: when entering the queue, you can directly enter the stack;
When leaving the queue, first judge whether the queue stack is empty. If
it is empty, pour the elements of the queue stack into the queue stack,
and then take out the top of the stack. If it is not empty, it means that
the last operation was also out of the queue, then take out the top of
the queue stack directly.
The advantage of this is to further simplify the code and eliminate unnecessary transformations.
"""
class MyQueue2:
def __init__(self):
self.entry = LinkStack() # 入队列 栈
self.out = LinkStack() # 出队列 栈
# 不a栈的元素转移到b栈
def transfer_stack(self, a, b):
while not a.stack_is_empty(): # 将a栈元素倒出,存入b栈
top = a.get_stack_top() # 获取a栈栈顶
a.stack_pop() # 出栈
b.stack_push(top) # 栈顶压入b栈
# 入队列
def queue_push(self, x):
self.entry.stack_push(x) # 元素直接加入入队列栈,入队列
# 出队列
def queue_pop(self):
if self.out.stack_is_empty():
self.transfer_stack(self.entry, self.out)
# 把元素从入队列栈倒入出队列栈
out_element = self.out.get_stack_top()
# 获取栈顶,就是要出队列的元素
self.out.stack_pop()
# 出栈,完成出队列
return out_element # 返回出队列元素
老板: 嗯,小伙子很不错。
老表: 谢谢老板。
# 当然,也许还有别的方法,比如建一个辅助的链表
# 欢迎你说出你的想法
# 程序入口,测试函数功能
if __name__ == "__main__":
s = MyQueue2() # 初始化一个MyQueue
s.queue_push(1)
s.queue_push(2)
s.queue_push(3)
s.queue_push(4)
# 入队列
print("当前队首元素(出队列)为:", s.queue_pop())
s.queue_push(666)
print("当前队首元素(出队列)为:", s.queue_pop())
print("当前队首元素(出队列)为:", s.queue_pop())
本文代码思路来自书籍《Python程序员面试宝典》,书中部分代码有问题,文中已经修改过了,并添加上了丰厚的注释,方便大家学习,后面我会把所有内容开源放到Github上,包括代码,思路,算法图解(手绘或者电脑画),时间充裕的话,会录制视频。
希望大家多多支持。
大家好,我是老表
觉得本文不错的话,转发、留言、点赞,是对我最大的支持。
欢迎关注微信公众号:简说Python
关注后回复:1024,可以领取精选编程学习电子书籍。