スタックとは、LIFO のADTで、データを挿入する push、一番最後に挿入したデータを取り出す pop というメソッドを持ちます。
キューとは、FIFO の ADT で、データを挿入する enqueue 、一番最初に挿入したデータを取り出す dequeue というメソッドを持ちます。
スタックを2つ組み合わせることで、キューを作ることができます。
まずは enqueue のためのスタックを用意し、5, 2, 10 を挿入しました。
| enqueue |
|---|
| 5 |
| 2 |
| 10 |
スタックなので pop で値を取り出すと 5 が取り出されます。
ここで、dequeue のためにもう一つスタックを用意し、このスタックが空の場合は enqueue のスタックから値を全て pop して挿入することにします。
上の状態にこの操作を適用すると、以下のような状態になります。
| enqueue | dequeue |
|---|---|
| 10 | |
| 2 | |
| 5 |
この状態であれば、pop で最初に挿入した値を取り出すことができます。
コードにまとめます。
class Stack(object):
def __init__(self):
self.stack = []
# O(1)
def push(self, data):
self.stack.append(data)
# O(1)
def pop(self):
data = self.stack[-1]
del self.stack[-1]
return data
# O(1)
def peek(self):
data = self.stack[-1]
return data
def __len__(self):
return len(self.stack)
class Queue(object):
def __init__(self):
self.enqueue_stack = Stack()
self.dequeue_stack = Stack()
def enqueue(self, data):
self.enqueue_stack.push(data)
def dequeue(self):
if len(self.enqueue_stack) == 0 \
and len(self.dequeue_stack) == 0:
raise Exception('Empty Queue')
if len(self.dequeue_stack) == 0:
while len(self.enqueue_stack) != 0:
self.dequeue_stack.push(self.enqueue_stack.pop())
return self.dequeue_stack.pop()
if __name__ == '__main__':
queue = Queue()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
queue.enqueue(4)
# 1
print(queue.dequeue())
# 2
print(queue.dequeue())
# 3
print(queue.dequeue())
# 4
print(queue.dequeue())
# Exception: Empty Queue
print(queue.dequeue())
再帰でも書けます。
再帰を使うと、見かけ上のスタックは一つになります。
ただし、関数の再帰的な呼び出しでスタックを使うので、実質的には上のループを使う場合と同様です。
class Stack(object):
def __init__(self):
self.stack = []
# O(1)
def push(self, data):
self.stack.append(data)
# O(1)
def pop(self):
data = self.stack[-1]
del self.stack[-1]
return data
# O(1)
def peek(self):
data = self.stack[-1]
return data
def __len__(self):
return len(self.stack)
class Queue(object):
def __init__(self):
self.stack = Stack()
def enqueue(self, data):
self.stack.push(data)
def dequeue(self):
if len(self.stack) == 0:
raise Exception('Empty Queue')
if len(self.stack) == 1:
return self.stack.pop()
popped = self.stack.pop()
dequeued = self.dequeue()
self.stack.push(popped)
return dequeued
if __name__ == '__main__':
queue = Queue()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
queue.enqueue(4)
# 1
print(queue.dequeue())
# 2
print(queue.dequeue())
# 3
print(queue.dequeue())
# 4
print(queue.dequeue())
# Exception: Empty Queue
print(queue.dequeue())