【Python】dequeでキューやスタックを実現する(collections.deque)
.jpg)
Pythonでキューやスタックを実現する際に利用できる collections モジュールの deque について解説します。
目次
キュー(queue)とスタック(stack)
deque の定義や使い方の説明の前にキュー (queue) と スタック (stack) について簡単に説明しておきます。キューやスタックについてご存じの方は読み飛ばしていただいて結構です。
キューとスタックは、データ格納と取り出しに関するデータ構造の一種となっています。それぞれの概要をまとめると以下のようになります。また、キューとスタックの概要図も示します。
| 名称 | 内容 |
|---|---|
| キュー(queue) | 先入れ先出し(FIFO: First In First Out)で管理するデータ構造 |
| スタック(stack) | 後入れ先出し(LIFO: Last In First Out)で管理するデータ構造 |

キューは最初に入れたデータから順に取りだすデータ構造で、よく先頭の人から順番に対応される待ち行列の話で説明がされます。上記図でいうと ①→② の順で入れたデータは、①→② の順でデータが取り出されます。先入れ先出しであることから FIFO (First In First Out) と言います。
一方で、スタックはキューとは逆で最後に入れたデータから順に取り出すデータ構造です。上記図でいうと ①→② の順で入れたデータは ②→① の順で取り出されます。後入れ先出しであることから LIFO (Last In First Out) と言います。
キューやスタックといったデータ構造を Python で実現しようとする場合、list 型の insert や pop を利用した実現を考えることができます。しかし、list 型は追加・削除で要素の移動が伴う可能性があるため、処理が非効率となる可能性があります。
効率的にキューやスタックを実現するために Python の collections モジュールには deque が使用できます。
本記事では、deque を用いたキューやスタックの実現方法について紹介します。
deque(collections モジュール)
キューやスタックの実装を例に deque の使い方を紹介していきます。deque という名称は、「double ended queue(両端キュー)」からきていて、デックと呼ばれます。
deque は内部的には二重のリンクリストとして実現されています。イメージの図にしてみると以下のようになります。

各要素は、要素同士の双方向のリンクを持っていて相互に参照することができます。そのため、要素へのアクセスは先頭または末尾からリンクをたどってアクセスします。
メソッドとしては以下のようなメソッドが用意されています。
| メソッド名 | 概要 |
|---|---|
append(x) | x を末尾に追加する |
appendleft(x) | x を先頭に追加する |
pop() | 末尾から値を取得し、削除する |
popleft() | 先頭から値を取得し、削除する |
clear() | 全ての値を削除する |
図と対応させてみてもらうと分かりやすいかと思いますが、データを追加する場合は append、データを取り出すときが pop です。なお、先頭の場合は appendleft、popleft のように left がつきます。図のように先頭が左という考え方になります。
deque は、前後のリンクを持っている構造上、先頭や末尾へのアクセスや追加/削除は早いですが、データの中央に近づくほどアクセスに時間がかかってしまうのが特徴があることを覚えておきましょう。
以降では、deque を用いたキュー(queue)とスタック(stack)の実装例を紹介していきますが、上の図のようなイメージを持ってもらうと理解がしやすいかと思います。
deque によるキュー(queue)操作
キュー (queue) の操作を deque を使用して実現するには以下のようにします。
import collections # dequeの作成 data = collections.deque() # データの追加 data.append(10) data.append(20) data.append(30) data.append(40) # 先頭からのデータ取り出し print(data) print(data.popleft()) print(data) print(data.popleft()) print(data)
【実行結果】 deque([10, 20, 30, 40]) 10 deque([20, 30, 40]) 20 deque([30, 40])
deque を使用するために collections モジュールのインポートが必要です。collections.deque() で deque のインスタンスを生成して使用します。
キューは、先入れ先出しの FIFO (First In First Out) ですので、データの追加は末尾にデータを追加する append メソッドを使用し、データを取り出すには先頭からデータを取り出す popleft メソッドを使用します。
このように deque を使用するとキューの操作を簡単に実現することができます。
deque によるスタック(stack)操作
スタック (stack) の操作を deque を使用して実現するには以下のようにします。
import collections # dequeの作成 data = collections.deque() # データの追加 data.append(10) data.append(20) data.append(30) data.append(40) # 末尾からのデータ取り出し print(data) print(data.pop()) print(data) print(data.pop()) print(data)
【実行結果】 deque([10, 20, 30, 40]) 40 deque([10, 20, 30]) 30 deque([10, 20])
キューの例と同様に、deque を使用するためにはまず collections モジュールのインポートが必要です。その後に collections.deque() で deque インスタンスを生成して使用します。
スタックは、後入れ先出しの LIFO (Last In Last Out) ですので、データの追加は末尾にデータを追加する append メソッドを使用し、データを取り出すには末尾から取り出す pop メソッドを使用します。
このように deque を使用するとスタックの操作を簡単に実現することができます。
deque の使用に関する注意点
deque には、上記で紹介してきたような append、pop 等の操作の他に、insert、remove、index 等のメソッドをサポートしています。
しかし、deque は構造上、先頭や末尾への操作は非常に高速ですが、それ以外の操作は不得意です。そのため、insert、remove、index などの操作を頻繁に使用するプログラムの場合はリストの方がデータ構造としては適しています。
要素数がそれほど多くない場合には、リストでも deque でもそれほど処理速度の差はないため、多くのアプリケーションではリストで問題ない可能性もあります。しかし、適切なデータ構造を選択するというのはプログラマとして重要な観点ですので、よく検討して deque を活用するようにしてください。
まとめ
Python でキューやスタックを実現する際に利用できる collections モジュールの deque について解説しました。
deque は「double ended queue(両端キュー)」のことで、各種メソッドが用意されているため、キューやスタックの操作が簡単に実現できます。
deque は構造上、先頭や末尾への操作は非常に高速ですが、それ以外の操作は不得意という特徴があります。データの途中の要素に頻繁にアクセスすることが必要な場合にはリストのが適していますので、deque の使用が妥当であるかは想定する操作にあわせてよく検討してください。
上記で紹介しているソースコードについては GitHub にて公開しています。参考にしていただければと思います。


.jpg)
.jpg)
.jpg)
.jpg)