dijkstra算法在基于堆的优先级队列中的查找时间

lookup time in heap based priority queue for dijkstra algorithm

本文关键字:优先级 队列 查找时间 于堆 算法 dijkstra      更新时间:2023-10-16

我想使用priority_queue作为dikjstra算法的顶点容器,在调用extractMin以获得顶点u之后,我找到所有相邻的顶点v,然后我可能会调用decreaseKey用于v,我知道decreaseKey花费O(lgN)时间,然而,在调用decreaseKey之前,我必须首先找到v的位置。

我使用std::vectorstd::make_heap/std::push_heap/std::pop_heap来维护优先级队列,使用这种数据结构,查找特定数据将花费O(N)时间,这将使O(lgN) decreaseKey变得毫无意义。

那么,在dikjstra算法顶点容器的常用方法是什么,或者我应该在class Vertex中添加一个成员来保持它在堆中的位置?

首先你不需要使用std::***_heap函数;STL中已经有priority_queue

对于更新堆中已经存在的值,可以插入索引和距离的pair s。并维护距离矢量,以验证距离是否仍然有效或已被更新;比如:

typedef struct {
    size_t index;   /* index of vertex and the distance at which */
    int dist;       /* the vertex was pushed to the heap         */
} value_t;
/* `a` has less priority than `b` if it is further away */
const auto comp = [](const value_t & a, const value_t & b){
    return b.dist < a.dist;
};
priority_queue<value_t, vector<value_t>, decltype(comp)> heap(comp);
/* the *most current* shortest distances for all nodes */
vector<int> dist(n, inf); 

那么Dikjstra循环应该是这样的:

while(!heap.empty()) {
    const auto top = heap.top();
    heap.pop();
    if(dist[top.index] < top.dist) {
          /* the node has already been added at a  */
          /* shorter distance therefore skip it    */
          continue;
    }
    /* process the node & its neighbors */
    /* push to the heap neighbors which get their `dist` deccreased */
}

确实,在堆中可能存在相同节点的多个副本(在不同的距离上,其中只有一个仍然有效);但是您可能会显示堆的大小是O(num. of edges),因此堆仍然会执行O(log num. of nodes)