How to implement O(logn) decrease-key operation for min-heap based Priority Queue?

You can do following: store a hashmap inside your heap that maps your heap values to heap indexes. Then you should extend your usual heap-logic just a bit:

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; 

BubbleUp(index) in case of DecreaseKey, and BubbleDown/Heapify(index) in case of IncreaseKey, to restore min-heap-property.

Here's my C# implementation: http://pastebin.com/kkZn123m

Insert and ExtractMin call Swap log(N) times, when restoring heap property. And you're adding O(1) overhead to Swap, so both operations remain O(log(n)). UpdateKey is also log(N): first you lookup index in a hashmap for O(1), then you're restoring heap property for O(log(N)) as you do in Insert/ExtractMin.

Important note: using values for index lookup will require that they are UNIQUE. If you're not ok with this condition, you will have to add some uniqueue id to your key-value pairs and maintain mapping between this uniqueue id and heap index instead of value-index mapping. But for Dijkstra it's not needed, as your values will be graph nodes and you don't want duplicate nodes in your priority queue.


Per this SO question it is unnecessary to have a decrease-key method in order to implement Dijkstra's Algorithm.

You can simply add an item to the priority queue as many times as necessary and keep track of which nodes you have visited to weed out the duplicates. The first time you actually visit a node by popping it off of the queue, you have found the shortest path to that node and can ignore all future occurrences of it on the priority queue.

Having many extra nodes on the priority queue is not much of a problem because it is an O(log N) structure. (You have to do about 20 comparisons for 1 million items and 30 comparison for 1 billion items.)

Edit: Following up on this question later, I'm a bit disappointed by my answer: all of those things will have to come off of the queue unless you do some special canipulations later. Like many things in life, it comes down to how you manage your memory and the costs associated with doing so. But the general point remains: decrease-key is not necessary, even if it might be desirable.