web-dev-qa-db-ja.com

実装方法O(logn) min-heapベースの優先度キューの減少キー操作?

Djikstraのアルゴリズムを実証するアプリケーションに取り組んでおり、それを使用するには、要素の値が減少したときにヒーププロパティを復元する必要があります。

複雑さに関する問題は、アルゴリズムが要素の値を変更するとき、内部構造(この場合はヒープ)内のその要素のインデックスが使用されることです優先キューは不明です。そのため、実際にdecrease-keyを実行する前に、インデックスを回復するために、O(n)検索を実行する必要があります。

さらに、操作に必要な実際のコードについては正確にはわかりません。優先度キューにD-Heap here を使用しています。疑似コードは役立ちますが、これを行う方法についてはJavaの例を参照してください。

45
jathanasiou

以下を行うことができます。ヒープvaluesをヒープインデックスにマッピングするハッシュマップをヒープ内に保存します。次に、通常のヒープロジックを少しだけ拡張する必要があります。

_on Swap(i, j): 
    map[value[i]] = j; 
    map[value[j]] = i;
_

_on Insert(key, value): 
    map.Add(value, heapSize) in the beginning;
_

_on ExtractMin: 
    map.Remove(extractedValue) in the end;
_

_on UpdateKey(value, newKey): 
    index = map[value]; 
    keys[index] = newKey; 
_

DecreaseKeyの場合はBubbleUp(index)IncreaseKeyの場合はBubbleDown/Heapify(index)は、最小ヒーププロパティを復元します。

これが私のC#実装です: http://Pastebin.com/kkZn123m

InsertおよびExtractMinは、ヒーププロパティを復元するときにSwap log(N)回呼び出します。また、スワップにO(1)オーバーヘッドを追加しているため、両方の操作はO(log(n))のままです。UpdateKeyはlog(N)です。 O(1)、Insert/ExtractMinで行うように、O(log(N))のヒーププロパティを復元しています。

重要な注意:インデックスルックアップに値を使用するには、値が一意である必要があります。この条件に満足できない場合は、キーと値のペアに一意のIDを追加し、値とインデックスのマッピングではなく、この一意のIDとヒープインデックス間のマッピングを維持する必要があります。しかし、Dijkstraの場合、値はグラフノードになり、優先度キューにノードを重複させたくないため、必要ありません。

31
ptkvsk

this SO question ダイクストラのアルゴリズムを実装するために減少キーメソッドを使用する必要はありません。

必要な回数だけアイテムを優先キューに追加し、訪問したノードを追跡して重複を排除できます。キューからノードをポップして初めて実際にノードにアクセスしたとき、そのノードへの最短パスが見つかり、優先キューでの今後の発生をすべて無視できます。

O(log N)構造体であるため、優先度キューに多くのノードを追加しても問題にはなりません。 (100万アイテムについては約20回、10億アイテムについては30回比較する必要があります。)

編集:後でこの質問をフォローアップすると、答えに少しがっかりしています。後でいくつかの特別な操作を行います。人生の多くのことと同様に、それはあなたの記憶を管理する方法とそうすることに関連するコストに帰着します。ただし、一般的なポイントは残ります。decrease-keyは、望ましい場合でもnecessaryではありません。

18
Richard

C++ stl make_heap()/ pop_heap()/ Push_heap()を使用している場合、ノードIDから下線ヒープベクトルのインデックスへのインデックスを保持する方法はありません。O(logn)キーの増加/キーの減少操作。

0
zach