私は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
ri Goren 驚くほど 上記 のように、Python stdlibは幸運なことに効率的なキューをすでに実装しています: collections.deque
=。
自分でホイールを転がしてホイールを作り直すことは避けてください。
dequeue()
およびenqueue()
メソッドの最悪の場合の時間の複雑さをO(1)に減らしますが、collections.deque
タイプはすでにそうしています。また、Cベースの伝統を考えると、スレッドセーフであり、おそらくより多くのスペースと時間の効率が向上します。enqueue()
メソッドをPythonリストの観点から実装すると、最悪の場合の時間の複雑さがO(n)。Cベースの配列から最後の項目を削除するため、Pythonリストは一定時間の操作であり、 Pythonリストの観点からのdequeue()
メソッドは、O(1)と同じ最悪の場合の時間の複雑さを保持しますが、enqueue()
はかわいそうに遅いままです。official deque
documentation を引用するには:
list
オブジェクトは同様の操作をサポートしますが、これらは高速の固定長操作用に最適化されており、O(n)pop(0)
およびinsert(0, v)
操作。
さらに重要なことに、deque
alsoは、初期化時に渡される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
APIの汎用ユーティリティの簡単なデモンストレーションとしてonlyが与えられます。
deque
クラスは 大幅に多くの機能 を提供します。
...反復、酸洗い、
len(d)
、reversed(d)
、copy.copy(d)
、copy.deepcopy(d)
、in演算子を使用したメンバーシップテスト、およびd[-1]
などの添え字参照。
シングルエンドまたはダブルエンドのキューが必要な場合は、deque
を使用するだけです。以上です。
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
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()
配列を使用したQueueの実装は次のとおりです。enqueue
とdequeue
はどちらも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