Easiest way of using min priority queue with key update in C++

前端 未结 4 1302
终归单人心
终归单人心 2020-12-02 04:20

Sometimes during programming contests etc., we need a simple working implementation of min priority queue with decrease-key to implement Dijkstra algorithm etc.. I often use

4条回答
  •  抹茶落季
    2020-12-02 05:05

    Well, as Darren already said, std::priority_queue doesn't have means for decreasing the priority of an element and neither the removal of an element other than the current min. But the default std::priority_queue is nothing more than a simple container adaptor around a std::vector that uses the std heap functions from (std::push_heap, std::pop_heap and std::make_heap). So for Dijkstra (where you need priority update) I usually just do this myself and use a simple std::vector.

    A push is then just the O(log N) operation

    vec.push_back(item);
    std::push_heap(vec.begin(), vec.end());
    

    Of course for constructing a queue anew from N elements, we don't push them all using this O(log N) operation (making the whole thing O(Nlog N)) but just put them all into the vector followed by a simple O(N)

    std::make_heap(vec.begin(), vec.end());
    

    The min element is a simple O(1)

    vec.front();
    

    A pop is the simple O(log N) sequence

    std::pop_heap(vec.begin(), vec.end());
    vec.pop_back();
    

    So far this is just what std::priority_queue usually does under the hood. Now to change an item's priority we just need to change it (however it may be incorporated in the item's type) and make the sequence a valid heap again

    std::make_heap(vec.begin(), vec.end());
    

    I know this is an O(N) operation, but on the other hand this removes any need for keeping track of an item's position in the heap with an additional data structure or (even worse) an augmentation of the items' type. And the performance penalty over a logarithmic priority update is in practice not that signficant, considering the ease of use, compact and linear memory useage of std::vector (which impacts runtime, too), and the fact that I often work with graphs that have rather few edges (linear in the vertex count) anyway.

    It may not in all cases be the fastest way, but certainly the easiest.

    EDIT: Oh, and since the standard library uses max-heaps, you need to use an equivalent to > for comparing priorities (however you get them from the items), instead of the default < operator.

提交回复
热议问题