web-dev-qa-db-ja.com

Pythonに効率的なキューを実装する

私はPythonでキューを実装しようとしましたが、問題が発生しています。

リストを使用してQueueデータ構造を実装しようとしていますが、enqueueおよびdequeue 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
10

ri Goren 驚くほど 上記 のように、Python stdlibは幸運なことに効率的なキューをすでに実装しています: collections.deque =。

してはいけないこと

自分でホイールを転がしてホイールを作り直すことは避けてください。

  • リンクリストの実装 。そうすることで、dequeue()およびenqueue()メソッドの最悪の場合の時間の複雑さをO(1)に減らしますが、collections.dequeタイプはすでにそうしています。また、Cベースの伝統を考えると、スレッドセーフであり、おそらくより多くのスペースと時間の効率が向上します。
  • Pythonリストの実装 。私は 下の注記 として、enqueue()メソッドをPythonリストの観点から実装すると、最悪の場合の時間の複雑さがO(n)。Cベースの配列から最後の項目を削除するため、Pythonリストは一定時間の操作であり、 Pythonリストの観点からのdequeue()メソッドは、O(1)と同じ最悪の場合の時間の複雑さを保持しますが、enqueue()はかわいそうに遅いままです。

official deque documentation を引用するには:

listオブジェクトは同様の操作をサポートしますが、これらは高速の固定長操作用に最適化されており、O(n) pop(0)およびinsert(0, v)操作。

さらに重要なことに、dequealsoは、初期化時に渡されるmaxlenパラメータを介して、最大長の標準サポートを提供します。キューサイズを制限するための手動試行の必要性(これは必然的に、if条件に暗黙の競合状態が原因でスレッドの安全性を損なう)。

何をすべきか

代わりに、次のように、標準のcollections.dequeタイプに関してQueueクラスを実装します。

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 AP​​Iの汎用ユーティリティの簡単なデモンストレーションとしてonlyが与えられます。

dequeクラスは 大幅に多くの機能 を提供します。

...反復、酸洗い、len(d)reversed(d)copy.copy(d)copy.deepcopy(d)、in演算子を使用したメンバーシップテスト、およびd[-1]などの添え字参照。

シングルエンドまたはダブルエンドのキューが必要な場合は、dequeを使用するだけです。以上です。

15
Cecil Curry

queue classでは、キューリストの代わりにヘッドノードとテールノードを保持できます。

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
4
Shaon shaonty

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()
1
Darshan N S

配列を使用した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
0
Yossarian42