IndexedPriorityQueue

アバター
GRAM
記事: 164
登録日時: 14年前
住所: 大阪

IndexedPriorityQueue

投稿記事 by GRAM » 14年前

プライオリティーキューとは挿入した要素の優先順位が高いものから順に取り出せるという
若干便利なキューですが、要素を突っ込んだら最後。もう削除したり優先順位を変更できないことが普通です
(std::priority_queueなど)

そこでとある本で読んだIndexedPriorityQueueというのを実装してみました。
アクセサという若干苦し紛れのクラスを用いることで優先順位を後から変更したり要素を削除できるようにしたプライオリティーキューです

CODE:

template  >
class IndexedPriorityQueue{
public:
	//アクセサ:これを利用して順位変更や削除を行える。イテレーターと異なり捜査能力や参照能力は付加されていない
	class Accessor;
public:
	//コンストラクタは特に何もない
	IndexedPriorityQueue();

	//要素をキューに追加する
	Accessor push(const ItemType& item);

	//アクセサを用いて要素の優先順位を再変更する
	void change_priority(const ItemType& item, const Accessor& a);

	//アクセサを用いて要素を削除する
	void erase(const Accessor& a);

	//もっとも優先順位の高い要素を削除する
	void pop();

	//もっとも優先順位の高い要素の参照を得る
	ItemType& top();
	const ItemType& top() const;

	//キューのサイズを得る
	unsigned int size() const;

	//キューが空かどうか
	bool empty() const;
};
見える部分だけだとあんな感じですが、実際にはこうなってます
► スポイラーを表示
こんな感じで使えます

CODE:

#include 
#include 

using namespace std;
int main(){
	//テンプレート引数には関数オブジェクトを使う(デフォルトは昇順)
	IndexedPriorityQueue> q;
	
	//10へのアクセサを取得(以降長いのでautoを使う)
	IndexedPriorityQueue>::Accessor acc10 = q.push(10);

	//アクセサは破棄しても構わない
	q.push(8);
	q.push(7);
	q.push(9);

	//6へのアクセサを取得
	auto acc6 = q.push(6);
	q.push(2);
	//4へのアクセサを取得
	auto acc4 = q.push(4);
	q.push(5);
	q.push(-3);
	q.push(2);
	q.push(1);


	//10を-10へ変更して並び替え
	q.change_priority(-10,acc10);
	//6を削除
	q.erase(acc6);
	//4へのアクセサをコピーして
	auto acc4Copy = acc4;
	//acc4で順位変更を行っても
	q.change_priority(-4,acc4);
	//コピーしたアクセサもちゃんと動作する。
	q.change_priority(-40,acc4Copy);


	while(!q.empty() ){
		cout << q.top() << endl;
		q.pop();
	}
	return 0;
}
出力は9,8,7,5,2,2,1,-3,-10,-40となり降順に値を取り出せます。
どの操作もO(logN)で行えます。(topとsizeとemptyは定数時間)
見ての通りアクセサを破棄すればほとんどstd::priority_queueと同じ動作をします。
探索アルゴリズムのダイクストラ法で若干活躍しますw
そしてC++0x早く来てほしい。

<追記>あ、若干コメントに不備があったので直しました
最後に編集したユーザー GRAM on 2011年4月27日(水) 23:38 [ 編集 1 回目 ]

xxx
記事: 26
登録日時: 14年前

Re: IndexedPriorityQueue

投稿記事 by xxx » 14年前

最短経路問題でヒープ内の順序入れ替える時が思いつかないんですが。