優先度付きキュー(priority queue)は、要素を優先度付きで追加し、要素を取り出すときは最も高い優先度を持つものから取り出されます。ただいったん格納した要素の優先度を変更したり要素がもつ値を変更することはできません。そこで今回は格納した要素の優先度を変更できる優先度つきキューを実装することにします。

優先度を変更したい要素を指定できるように要素には一意のキーをもたせます。同じキーをもつ要素を追加する場合は要素の更新として処理をします。優先度付きキューもキューである以上、格納した要素にランダムアクセスすることはできません。そこで辞書を併用することでキーから要素を取得できるようにします。また要素を削除するときも優先度がもっとも高い要素(優先度の値が最小の要素)しか削除できないので要素に死亡フラグをもたせることで任意の要素を削除できるようにします。

Elementクラスの定義

Elementクラスを定義します。フィールド変数にキー、データとしての値、優先度、死亡フラグを定義しています。

UpdateablePriorityQueueクラス

UpdateablePriorityQueueクラスの本体部分です。フィールド変数とコンストラクタを示します。

最初に述べたとおり PriorityQueueとDictionaryをフィールド変数に入れています。またPriorityQueue.Dequeue()は設定したPriorityが最小の要素を取り除き、戻り値としてこれを返します。ただPriorityが最大のものを取り出したい場合もあるのでコンストラクタの引数で変更できるようにしています。

引数で指定したキーをもつ要素があるのか、その要素の値、優先度を取得するメソッドを示します。

要素を取り除く処理を示します。ここでは要素に死亡フラグをセットして

要素を追加する処理を示します。同じキーをもつ要素があるかもしれないのでRemoveを呼び出しています。そのあとElementオブジェクトを生成して辞書とPriorityQueueに追加しています。要素を更新するUpdateメソッドもEnqueueメソッドと同じ処理をしています。

優先度がもっとも高い要素を取得する処理を示します。

PriorityQueue.Peek()で取得した要素にすでに死亡フラグがセットされている場合、これは削除された要素なので取り出してそのまま捨てています。死亡フラグがセットされていない要素が見つかったらそれを返します。

優先度がもっとも高い要素を取り除く処理を示します。

Peek()を実行してPriorityQueueのなかに要素がある場合はPeek()が返した要素を取り除き、それを戻り値として返します。Peek()がnullを返したりPriorityQueueが空の場合はnullを返します。

格納されている要素の数を返す処理を示します。

使ってみる

E – Best Performances

解法ですが、配列 の要素を大きい順に並べたときに K 番目までになるもの(Larges)とそうでないもの(Smalls)にわけます。値が更新されたらLargesの最小値とSmallsの最大値を比較します。もしSmallsの最大値のほうがLargesの最小値よりも大きい場合は所属するグループを入れ替えます。

配列の値の更新とLarges の最小値とSmallsの最大値の取得は今回実装した要素の優先度を変更できる優先度つきキューで実現できます。