python相关的栈与队列了解
In case of stack, list implementation works fine and provides both append() and pop() in O(1) time. When we use deque implementation, we get same time complexity.
But when it comes to queue, the above list implementation is not efficient. In queue when pop() is made from the beginning of the list which is slow. This occurs due to the properties of list, which is fast at the end operations but slow at the beginning operations, as all other elements have to be shifted one by one.
So, we prefer the use of dequeue over list, which was specially designed to have fast appends and pops from both the front and back end.
Python实现stack更多方法:https://www.geeksforgeeks.org/stack-in-python/?ref=ml_lbp
Python实现queue更多方法:https://www.geeksforgeeks.org/queue-in-python/?ref=ml_lbp
简洁的概括:https://juejin.cn/s/stack%20and%20queue%20in%20python
下面的代码通过了,但是deque为空的判断还有疑惑,比如deque中元素为空了,但是使用is None判断是False,那为啥使用if XX 进行判断的时候可以准确知道还有没有元素?
if x: #x is treated True except for all empty data types [],{},(),'',0 False, and None
if x is not None # which works only on None
参考文档:https://stackoverflow.com/questions/7816363/if-a-vs-if-a-is-not-none
if x 用来判断x是True还是False,与None无关。而Python中事先定义了一些为False的值,这些值如下:
其它所有值都是True。而if x is None则是判断x是否为None
文档:https://bobbyhadz.com/blog/python-check-if-none
这个文档中还提到的小知识:判断是否为None的时候用is或者is not,is相当于判断引用地址是否一样,None在Python中是唯一的。==符号调用了equal函数,判断的是值是否一样。id()可以查看Python在cpython内存空间上的地址
题目保证了每次调用都不可能为空,所以不用进行空的判断
class MyQueue:
def __init__(self):
# 队列的初始化按照题目要求有两个栈
from collections import deque
self.stack1 = deque()
self.stack2 = deque()
def push(self, x: int) -> None:
self.stack1.append(x)
def pop(self) -> int:
# 如果stack2不为空,则可以直接弹出栈顶元素。否则需要stack1导入stack2
if self.stack2:
return self.stack2.pop()
else:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
def peek(self) -> int:
if self.stack2:
return self.stack2[-1]
else:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2[-1]
def empty(self) -> bool:
if len(self.stack1) == 0 and len(self.stack2) == 0:
return True
else:
return False
为空的代码也可以改为下面这样:
def empty(self) -> bool:
if not self.stack1 and not self.stack2:
return True
else:
return False
看了代码之后发现的小技巧:pop和peek代码重复了一部分,可以复用,以后改进吧
和两个栈模拟队列差别有点大,两个队列模拟栈得倒腾两次才行,在模拟pop操作的时候,需要把一个队列的元素只保留一个,其它的移到另一个辅助队列,在得到这个保留的元素之后,主队列赋值为辅助队列的值。
关于Python语言的又一个注意点出现了,在一个队列赋值给另一个队列的时候,这个时候赋值的是引用,可以看下面的代码
print(id(self.queue1), id(self.queue2))
self.queue1 = self.queue2
print(id(self.queue1), id(self.queue2))
代码如下
class MyStack:
def __init__(self):
# 按照题目要求初始化两个队列
from collections import deque
self.queue1 = deque()
self.queue2 = deque() # 辅助队列
def push(self, x: int) -> None:
self.queue1.append(x)
def pop(self) -> int:
# 将队列1中的元素只保留一个,其它的都放到队列2
for _ in range(len(self.queue1)-1):
self.queue2.append(self.queue1.popleft())
res = self.queue1.popleft()
# 重新恢复原状
self.queue1, self.queue2 = self.queue2, self.queue1
while self.queue2:
self.queue2.popleft()
return res
def top(self) -> int:
# 将队列1中的元素只保留一个,其它的都放到队列2
for _ in range(len(self.queue1) - 1):
self.queue2.append(self.queue1.popleft())
res = self.queue1.popleft()
# 重新恢复原状
self.queue1, self.queue2 = self.queue2, self.queue1
while self.queue2:
self.queue2.popleft()
self.queue1.append(res)
return res
def empty(self) -> bool:
return not self.queue1
注:上面的代码在改变两个队列交换方式之后可优化
只要在弹出元素的时候保留最后一个元素,将其它弹出元素放在同一个队列中就行。比两个队列的实现更方便
class MyStack:
def __init__(self):
# 一个队列
from collections import deque
self.queue = deque()
def push(self, x: int) -> None:
self.queue.append(x)
def pop(self) -> int:
for _ in range(len(self.queue)-1):
self.queue.append(self.queue.popleft())
return self.queue.popleft()
def top(self) -> int:
for _ in range(len(self.queue) - 1):
self.queue.append(self.queue.popleft())
res = self.queue.popleft()
self.queue.append(res)
return res
def empty(self) -> bool:
return not self.queue