我想使用priority_queue作为dikjstra算法的顶点容器,在调用extractMin
获取顶点u
之后,我找到所有相邻的顶点v
,然后我可能会调用{对于decreaseKey
{1}},我知道v
花费O(lgN)时间,但在调用decreaseKey
之前,我必须首先找到decreaseKey
的位置
我使用v
和std::vector
来维护priority_queue,使用这种数据结构来查找特定数据将花费O(N)时间,这将使O(lgN){{1无意义。
那么,dikjstra算法中顶点容器的常用方法是什么,还是应该在std::make_heap/std::push_heap/std::pop_heap
中添加一个成员来保持其在堆中的位置?
答案 0 :(得分:0)
首先,您不需要使用std::***_heap
个函数; STL中已有priority_queue
。
至于更新堆中已有的值,您可以插入索引和距离pair
。并保持距离向量以验证距离是否仍然有效或已更新;类似的东西:
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)
。