PythonでPriorityQueue
PythonでPriorityQueueを使おうと思ったら割と微妙な感じだったので書いてみる。
PriorityQueueとは優先順キューのこと。(優先順位にしたがって要素が追加削除できるキュー
ヒープアルゴリズムによって制御されており、
最小値を得ながら要素を追加していきたい、
なんていうときに使う。
どうしてこれが有用かというと、探索ルーチンなどのような場合に、
現在最小(最優先のもの)を探しながら見つかった要素をQueueに溜め込む、
なんていうときに単純なlistでは効率的にできないのだが、
これを解決する。
毎回ソートしたり、適切な場所に挿入するようなappendを書くよりずっと良い。
これには用意されているモジュールheapqを使う。
関数化されているので、heappushとheappopでデータを操作する簡易クラスを定義してみた。
from heapq import heappush, heappop from random import randint from time import time class PriorityQueue(object): def __init__(self): self.queue = [] def push(self, value): heappush(self.queue, value) def pop(self): return heappop(self.queue) def __len__(self): return len(self.queue) def __contains__(self, item): return item in self.queue #... class Foo(object): def __init__(self, index, value): self.index = index self.value = value def __str__(self): return "Foo%02d(%d)" % (self.index, self.value) def __le__(self, other): return self.value <= other.value queue = PriorityQueue() data = [1,3,5,7,9,2,100,104,1000,2000,999,999,999,0,45] for index, value in enumerate(data): queue.push(Foo(index, value)) while len(queue) > 0: foo = queue.pop() print foo
大小判定に__le__が使われているようなので要素に対する__le__を定義してある。
結果はこんな感じ。
Foo13(0)
Foo00(1)
Foo05(2)
Foo01(3)
Foo02(5)
Foo03(7)
Foo04(9)
Foo14(45)
Foo06(100)
Foo07(104)
Foo11(999)
Foo10(999)
Foo12(999)
Foo08(1000)
Foo09(2000)
popする際に適切な並びになっていることがわかる。
ただし、heapに使っているlistが常にソートされているわけではないことに注意。
あくまでpushやpopの際に適切な挿入や削除を行ってくれるだけ。
これだけで単にlistに挿入やソート済みlistを使うより何十倍も速くなる。
検証プログラムは時間があれば。