Python中的O(1)整数的可索引deque

时间:2012-05-04 17:05:35

标签: python collections

我有什么选择?我需要调用很多append s(到右端)和popleft s(从左端开始,自然而然),还要从存储中间读取,这将稳定增长,根据算法的性质。我想在O(1)中进行所有这些操作。

我可以在循环寻址的数组中简单地用C实现它(这是什么字?),它会在它满时自动增长;但是Python怎么样?其他语言的指针也很受欢迎(我意识到“集合”标签更像Java等,并且会更喜欢比较,但作为次要目标)。

我来自Lisp背景,并且惊讶地发现在Python中从列表中删除头元素是O(n)操作。 deque可能是一个答案,但文档说中间的访问权限为O(n)。还有什么别的,预先建好的吗?

3 个答案:

答案 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)