我有什么选择?我需要调用很多append
s(到右端)和popleft
s(从左端开始,自然而然),还要从存储中间读取,这将稳定增长,根据算法的性质。我想在O(1)
中进行所有这些操作。
我可以在循环寻址的数组中简单地用C实现它(这是什么字?),它会在它满时自动增长;但是Python怎么样?其他语言的指针也很受欢迎(我意识到“集合”标签更像Java等,并且会更喜欢比较,但作为次要目标)。
我来自Lisp背景,并且惊讶地发现在Python中从列表中删除头元素是O(n)
操作。 deque
可能是一个答案,但文档说中间的访问权限为O(n)
。还有什么别的,预先建好的吗?
答案 0 :(得分:7)
你可以使用两个python列表获得一个摊销的O(1)数据结构,一个持有双端队列的左半部分,另一个持有右半部分。前半部分反向存储,因此双端队列的左端位于列表的后面。像这样:
class mydeque(object):
def __init__(self):
self.left = []
self.right = []
def pushleft(self, v):
self.left.append(v)
def pushright(self, v):
self.right.append(v)
def popleft(self):
if not self.left:
self.__fill_left()
return self.left.pop()
def popright(self):
if not self.right:
self.__fill_right()
return self.right.pop()
def __len__(self):
return len(self.left) + len(self.right)
def __getitem__(self, i):
if i >= len(self.left):
return self.right[i-len(self.left)]
else:
return self.left[-(i+1)]
def __fill_right(self):
x = len(self.left)//2
self.right.extend(self.left[0:x])
self.right.reverse()
del self.left[0:x]
def __fill_left(self):
x = len(self.right)//2
self.left.extend(self.right[0:x])
self.left.reverse()
del self.right[0:x]
我不能100%确定这段代码与python列表的摊销性能之间的交互是否真的导致每个操作都有O(1),但我的直觉是这样说的。
答案 1 :(得分:3)
访问lisp列表的中间也是O(n)。
Python list
是数组列表,这就是为什么弹出头部是昂贵的(弹出尾部是恒定的时间)。
你正在寻找的是一个在头部有(摊销)恒定时间删除的数组;这基本上意味着你将不得不在list
之上构建一个使用延迟删除的数据结构,并且能够在队列为空时回收延迟删除的插槽。
或者,使用散列表和几个整数来跟踪当前连续的键范围。
答案 2 :(得分:0)
Python's Queue Module可能会对您有所帮助,但我不确定访问权限是否为O(1)
。