在Python中实现高效的队列

时间:2017-08-15 08:10:42

标签: python queue

我一直在尝试用Python实现队列,而且我遇到了一个问题。

我正在尝试使用列表来实现Queue数据结构,但是我无法弄清楚如何进行enqueuedequeue O(1)操作。

我在网上看到的每个例子似乎只是附加了enqueue操作,并从dequeue操作列表中删除了第一个元素。但这会使dequeue操作O(n)(其中n是列表的大小)正确吗?

我错过了一些基本的东西吗?或者您是否必须使用LinkedLists有效地实现队列?

import unittest

class Queue():
    def __init__(self):
        self._queue = []
        self.size = 0
        self.maxSize = 10

    def enqueue(self, item):
        if self.size < self.maxSize:
            self._queue.append(item)

    def dequeue(self):
        '''
        Removes an item from the front of the list. Remove first element of
        the array
        '''
        first = self._queue[0]
        del self._queue[0]
        return first

7 个答案:

答案 0 :(得分:5)

作为Uri Goren精明地noted above,Python stdlib已经为您的幸运实现了一个高效的队列:collections.deque

什么不该做

通过自己手动滚动来避免重新发明轮子:

  • Linked list implementation。虽然这样做可以将dequeue()enqueue()方法的最坏情况时间复杂度降低到O(1),但collections.deque类型已经这样做了。鉴于其基于C的传统,它也是线程安全的,并且可能更具空间和时间效率。
  • Python list implementation。正如我note below一样,根据Python列表实现enqueue()方法会将最坏情况下的时间复杂度增加到 O(n)。因为从C中删除最后一项基于数组的数组,因此Python列表是一个常量时间操作,根据Python列表实现dequeue()方法保留了与O(1)相同的最坏情况时间复杂度。但谁在乎? enqueue()仍然非常缓慢。

引用official deque documentation

  

虽然list个对象支持类似的操作,但它们针对快速固定长度操作进行了优化,并导致pop(0)insert(0, v)操作的O(n)内存移动成本,从而改变了这两种操作的大小和基础数据表示的位置。

更关键的是,deque 通过初始化时传递的maxlen参数提供对最大长度的开箱即用支持,从而无需手动操作尝试限制队列大小(由于条件中隐含的竞争条件,这不可避免地会破坏线程安全性。)

怎么做

相反,请按照以下标准Queue类型实施您的collections.deque课程:

from collections import deque

class Queue():
    '''
    Thread-safe, memory-efficient, maximally-sized queue supporting queueing and
    dequeueing in worst-case O(1) time.
    '''


    def __init__(self, max_size = 10):
        '''
        Initialize this queue to the empty queue.

        Parameters
        ----------
        max_size : int
            Maximum number of items contained in this queue. Defaults to 10.
        '''

        self._queue = deque(maxlen=max_size)


    def enqueue(self, item):
        '''
        Queues the passed item (i.e., pushes this item onto the tail of this
        queue).

        If this queue is already full, the item at the head of this queue
        is silently removed from this queue *before* the passed item is
        queued.
        '''

        self._queue.append(item)


    def dequeue(self):
        '''
        Dequeues (i.e., removes) the item at the head of this queue *and*
        returns this item.

        Raises
        ----------
        IndexError
            If this queue is empty.
        '''

        return self._queue.pop()

证据是地狱般的布丁:

>>> queue = Queue()
>>> queue.enqueue('Maiden in Black')
>>> queue.enqueue('Maneater')
>>> queue.enqueue('Maiden Astraea')
>>> queue.enqueue('Flamelurker')
>>> print(queue.dequeue())
Flamelurker
>>> print(queue.dequeue())
Maiden Astraea
>>> print(queue.dequeue())
Maneater
>>> print(queue.dequeue())
Maiden in Black

独自危险

实际上,也不这样做。

最好只使用原始deque对象,而不是尝试在Queue包装器中手动封装该对象。上面定义的Queue类只有 作为deque API的通用实用程序的简单演示。

deque课程提供significantly more features,包括:

  

...迭代,腌制,len(d)reversed(d)copy.copy(d)copy.deepcopy(d),使用in运算符进行成员资格测试,以及d[-1]等下标引用}。

只需在需要单端或双端队列的任何地方使用deque。就是这样。

答案 1 :(得分:2)

您可以在queue class

中保留head and tail节点而不是队列列表
class Node(object):
  def __init__(self, item = None):
    self.item = item
    self.next = None
    self.previous = None


class Queue(object):
  def __init__(self):
    self.length = 0
    self.head = None
    self.tail = None

  def enqueue(self, x):
    newNode = Node(x)
    if self.head == None:
      self.head = self.tail = newNode
    else:
      self.tail.next = newNode
      newNode.previous = self.tail
      self.tail = newNode
    self.length += 1


  def dequeue (self):
    item = self.head.item
    self.head = self.head.next 
    self.length -= 1
    if self.length == 0:
      self.last = None
    return item

答案 2 :(得分:0)

使用Python中的列表执行队列,并按照内置队列数据结构处理入队和入队:

    class queue:

def __init__(self, max_size, size=0, front=0, rear=0):
    self.queue = [[] for i in range(5)] #creates a list [0,0,0,0,0]
    self.max_size = max_size
    self.size = size
    self.front = front
    self.rear = rear


def enqueue(self, data):
    if not self.isFull():
        self.queue[self.rear] = data
        self.rear = int((self.rear + 1) % self.max_size)
        self.size += 1
    else:
        print('Queue is full')

def dequeue(self):
    if not self.isEmpty():
        print(self.queue[self.front], 'is removed')
        self.front = int((self.front + 1) % self.max_size)
        self.size -= 1
    else:
        print('Queue is empty')

def isEmpty(self):
    return self.size == 0

def isFull(self):
    return self.size == self.max_size

def show(self):
    print ('Queue contents are:')
    for i in range(self.size):
        print (self.queue[int((i+self.front)% self.max_size)])

    # driver program
    q = queue(5)
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    q.enqueue(4)
    q.enqueue(5)
    q.dequeue()
    q.show()

答案 3 :(得分:0)

这是我使用数组的Queue实现,enqueuedequeue都是O(1)操作。该实现基于CLRS。

class Queue:
    def __init__(self, length):
        """a queue of at most n elements using an array of n+1 element size"""
        self.length = length
        self.queue = [None]*(length+1)
        self.head = 0
        self.tail = 0

    def enqueue(self, x):
        if self.is_full():
            return 'Overflow'
        self.queue[self.tail] = x
        if self.tail == self.length:
            self.tail = 0
        else:
            self.tail = self.tail + 1

    def dequeue(self):
        if self.is_empty():
            return 'Underflow'
        x = self.queue[self.head]
        if self.head == self.length:
            self.head = 0
        else:
            self.head = self.head + 1
        return x

    def is_empty(self):
        if self.head == self.tail:
            return True
        return False

    def is_full(self):
        if self.head == self.tail+1 or (self.head == 0 and self.tail == self.length):
            return True
        return False

答案 4 :(得分:0)

# Linear Queue Implementation using Array
class Queue:
    """Class with List as Array """
    def __init__(self):
        self.v_list=[]
    """Storing the in FIFO order"""
    def enqueue(self,value):
        self.v_list.append(value)
   """Removing Element from Queue in FIFO order"""
    def dequeue(self):
        if len(self.v_list)==0:
            print('Queue is Empty')
            return
        self.v_list.pop(0)

    def print_queue(self):
        print(self.v_list)

    def size_of_queue(self):
        return print(len(self.v_list))

object_queue=Queue()
object_queue.enqueue(0)
object_queue.enqueue(1)
object_queue.enqueue(2)
object_queue.enqueue(3)
object_queue.enqueue(4)
object_queue.enqueue(5)
object_queue.print_queue()
object_queue.dequeue()
object_queue.print_queue()
object_queue.dequeue()
object_queue.print_queue()
object_queue.size_of_queue()

#Circular Queue Implementation using Array
class CircularQueue():
    def __init__(self):
        """Class to hold the Postions for insert and delete"""
        self.start_pointer=0
        self.end_pointer=-1
        self.queue_list=[]
    """Storing the element in Circular order, with circular we can remove empty Block"""
    def enqueue(self,value):
        if len(self.queue_list)>10:
            print("Circular Queue is Full")
            return
        """Checking for Empty Block in Array and storing data and reseting the stat end point to process the element"""
        if 'None' in self.queue_list:
            self.queue_list[self.end_pointer]=value
            self.end_pointer+=1
        else:
            self.queue_list.append(value)
            self.end_pointer+=1
    """Removing element In FIFO order and reseting start ending point"""
    def dequeue(self):
        #self.queue_list.replace(self.queue_list[self.start_pointer],None)
        self.queue_list = [str(sub).replace(str(self.queue_list[self.start_pointer]),'None') for sub in self.queue_list] 
        self.start_pointer+=1
        for i ,j in enumerate(self.queue_list):
            if j=='None':
                self.end_pointer=i
                break
    """For Printing Queue"""            
    def print_cq(self):
        if len(self.queue_list)>10:
            print("Circular Queue is Full")
            return
        print(self.queue_list,self.start_pointer,self.end_pointer)


cir_object=CircularQueue()
cir_object.enqueue(0)
cir_object.enqueue(1)
cir_object.enqueue(2)
cir_object.enqueue(3)
cir_object.enqueue(4)
cir_object.enqueue(5)
cir_object.enqueue(6)
cir_object.enqueue(7)
cir_object.enqueue(8)
cir_object.enqueue(9)
#cir_object.print_cq()
cir_object.dequeue()
cir_object.dequeue()
cir_object.print_cq()
cir_object.enqueue(15)
cir_object.enqueue(20)
cir_object.print_cq()

答案 5 :(得分:0)

class Queue:
    def __init__(self,no):
        self.no = no 
        self.SQueue = []
        self.front = -1
        self.rear = -1
    def insert(self):
        if self.rear == self.no -1:
            print("Queue is Full.....")
        else:           
            if self.front == -1:
                self.front = 0
                self.rear = 0
            else :
                self.rear += 1
            n = int(input("enter an element :: "))
            self.SQueue.insert(self.rear, n)

    def delete(self):
        if self.front == -1 and self.front == no - 1:
            print("Queue is Empty.....")
        else:
            self.SQueue.pop(self.front)
            self.front +=1
    def disp(self):
        if self.front == -1 and self.front == no - 1:
            print("Queue is Empty.....")
        else:
            print("REAR \tELEMENT")
            for i in range(len(self.SQueue)):
                print(i," \t",self.SQueue[i])

no = int(input("ENTER  Size :: "))
q = Queue(no)
while(True):
    print(" 1: INSERT ")
    print(" 2: DELETE ")
    print(" 3: PRINT ")
    print(" 4: EXIT ")
    option = int(input("enter your choice :: "))

    if option == 1:
        q.insert()
 
    elif option == 2:
        q.delete()

    elif option == 3:
        q.disp()

    elif option == 4:
        print("you are exit!!!!!")
        break
    else:
        print("Incorrect option")
 

答案 6 :(得分:-2)

在出队方法中没有任何循环。您只需要执行列表操作。因此,出队的时间复杂度也是O(n)(线性)。

class Queue:
    def __init__(self):
       self.items=[]
    def enqueue(self,item):
       self.items.append(item)
    def dequeue(self):
       return self.items.pop(0)
    def isEmpty(self):
       return self.items==[]
    def __len__(self):
       return len(self.items)