キュー(Queue) はデータの中で最初に入ったものが最初に取り出される、 先入れ先出し(First In First Out: FIFO) のデータ構造
キューの末尾に要素を追加することを エンキュー(enqueue) といい、
キューの先頭から要素を取り出すことを デキュー(dequeue) という。
実装例¶
Pythonでは、シンプルなキューとして collections パッケージのdequeが存在する。
また queueパッケージのQueueというクラスも存在する。
collections.dequeue はスレッドセーフではなく、 queue.Queue はスレッドセーフなのが主な違い
from collections import deque
q = deque()
q.append("A")
q.append("B")
print(q.popleft()) # A
print(q.popleft()) # BA
B
from queue import Queue
q = Queue()
q.put("A")
q.put("B")
print(q.get())
print(q.get())A
B
計算量¶
キューは内部的に連結リスト(または双方向キュー)で実装されるため、先頭・末尾へのアクセスがO(1)になる。
| 操作 | 計算量 | 説明 |
|---|---|---|
enqueue | 末尾への追加 | |
dequeue | 先頭からの取り出し | |
| peek(先頭参照) | 先頭要素の参照(取り出しなし) | |
is_empty | 空かどうかの確認 | |
| サイズ取得 | 要素数の取得 | |
| 探索 | 特定の要素を見つけるには全走査が必要 |
Pythonの queue.Queue は内部で collections.deque を使用しており、enqueue・dequeueともに償却 。
利用例¶
例1: タスクの順番処理¶
受け付けた順にタスクを処理する。新しいタスクは末尾に追加し、処理は先頭から行う。
from collections import deque
queue = deque()
# タスクを受け付ける
for task in ["タスクA", "タスクB", "タスクC"]:
queue.append(task)
# 受け付けた順に処理
while queue:
task = queue.popleft()
print(f"処理中: {task}")例2: 最短ステップ数(BFS)¶
スタート地点からゴールまで何ステップで到達できるか求める。
1ステップで +1 か +2 だけ進める場合に、位置 0 から位置 n まで最短何ステップかかるか。
from collections import deque
def min_steps(goal):
queue = deque([(0, 0)]) # (現在地, ステップ数)
visited = {0}
while queue:
pos, steps = queue.popleft()
if pos == goal:
return steps
for next_pos in [pos + 1, pos + 2]:
if next_pos <= goal and next_pos not in visited:
visited.add(next_pos)
queue.append((next_pos, steps + 1))
print(min_steps(5)) # 3 (0→2→4→5)
print(min_steps(10)) # 5 (0→2→4→6→8→10)