[データ構造] キュー

スタック スタックは、コンピュータで用いられる基本的なデータ構造の1つで、データを後入れ先出し(LIFO: Last In First Out;FILO: First In Last Out)の構造で保持するものである。抽象データ型としてのそれを指すこ...

キュー

キュー: queue)、あるいは待ち行列コンピュータの基本的なデータ構造の一つ。データを先入れ先出し[1]のリスト構造で保持するものである。キューからデータを取り出すときには、先に入れられたデータから順に取り出される。キューにデータを入れることをエンキュー[2]、取り出すことをデキュー[3]という。

出典: フリー百科事典『ウィキペディア(Wikipedia)』

ADTとしてのキューは、先入先出/FIFO/First In First Out でデータを保持する構造を持ち、キューにデータを挿入するenqueue、キューからデータを取り出す dequeue、次に取り出すデータを確認するpeek という基本的な操作を持ちます。

動的配列や連結リストを土台にして実装されます。

幅優先探索 というアルゴリズムを実装する際に使われます。

プリンタへの出力処理や、ウィンドウシステムのメッセージハンドラ、プロセスの管理など、データを入力された順番通りに処理する必要がある処理に用いられる。

出典: フリー百科事典『ウィキペディア(Wikipedia)』

enqueue

キューの一番最後に新しいデータを加えます。\( O(1) \) で実行できます。

dequeue

キューの一番最初のデータ(一番古いデータ、つまり一番最初に入ったデータ)を取り出します( 先入先出/FIFO/First In First Out )。 \( O(1) \) で実行できます。

取り出したデータはキューから削除されます。

peek

キューの一番最初のデータ(一番古いデータ、つまり一番最初に入ったデータ)を確認します。 \( O(1) \) で実行できます。

dequeueと異なり、データは削除されません。

キューの実装

Python でリストを持ちいてキューを実装してみます。

class Queue(object):

    def __init__(self):
        self.queue = []

    # O(1)
    def enqueue(self, data):
        self.queue.append(data)

    # O(N)
    def dequeue(self):
        data = self.queue[0]
        del self.queue[0]
        return data

    # O(1)
    def peek(self):
        data = self.queue[0]
        return data


if __name__ == '__main__':
    queue = Queue()
    queue.enqueue(1)
    queue.enqueue(2)
    queue.enqueue(3)
    
    # 1
    print(queue.peek())
    print(queue.dequeue())
    
    # 2
    print(queue.peek())
    print(queue.dequeue())
    
    # 3
    print(queue.peek())
    print(queue.dequeue())
    
    # IndexError
    print(queue.peek())
    print(queue.dequeue())

このコードで、それぞれの操作自体は想定通りに行われます。

しかしこのコードでは、enqueue peek は\( O(1) \) で行うことができますが、dequeue 、つまり先頭のデータの削除は Python のリストの性質上\( O(N)\)になってしまいます。

よって、Python でキューを扱うため、deque というモジュールが用意されており、このモジュールを使うことで dequeue の操作が\(O (1)\) で実行できます。

deque

class collections.deque([iterable[, maxlen]])

5.1.2. リストをキューとして使う

CPythonでは、 deque オブジェクトは、双方向連結リストとして実装されており、双方向連結リストなので、リストの両端へのアクセスやデータの挿入・削除を \( O(1) \) で行うことができるようになっています。

しかし、連結リストなのでリストの真ん中の方へのアクセスは\( O(N) \) となってしまい、ランダムアクセスには適していません。

cpython/Modules/_collectionsmodule.c

以下はとても分かりやすいです。

Pythonのdequeでキュー、スタック、デック(両端キュー)を扱う

二分探索木 二分探索木(にぶんたんさくぎ、英:binary search tree)は、コンピュータプログラムにおいて、「左の子孫の値 ≤ 親の値 ≤ 右の子孫の値」という制約を持つ二分木である。探索木のうちで最も基本的な木構造である。 出典: フリ...