Prim和Dijkstra图算法的区别

时间:2015-07-30 13:16:53

标签: algorithm graph

我正在阅读Cormen书中的图算法。下面是该书的伪代码

MST的Prim算法

MST-PRIM (G, w, r)

for each u in G.V
  u.key = infinity
  u.p = NIL

r.key = 0
Q = G.V
while Q neq null
  u = EXTRACT-MIN(Q)
  for each v in G.Adj[u]
    if (v in Q) and (w(u,v) < v.key)
      v.p = u
      v.key = w(u,v)

Dijkstra算法找到单源最短路径。

INITIALIZE-SINGLE-SOURCE (G,s)
  for each vertex v in G.V
    v.d = infinity
    v.par = NIL
  s.d = 0

DIJKSTRA (G, w, s)
  INITIALIZE-SINGLE-SOURCE(G,s)
  S = NULL
  Q = G.V
  while Q neq null
    u = EXTRACT-MIN(Q)
    S = S U {u}
    for each vertex v in G.Adj[u]
      RELAX(u,v,w)

我的问题是,为什么我们要检查顶点是否属于Q(v in Q),即顶点不属于树,而在Dijkstra算法中我们不检查它。

任何原因,为什么?

3 个答案:

答案 0 :(得分:2)

名为PrimDijkstra的算法首先解决了不同的问题。 'Prim'找到无向图的最小生成树,而'Disjkstra'解决具有非负边权重的有向图的单源最短路径问题。

答案 1 :(得分:2)

在两种算法中,队列Q包含所有尚未“完成”的顶点,即根据常用术语的白色和灰色(参见here)。

在Dijkstra的算法中,黑色顶点不能放松,因为如果可能的话,这意味着它的距离预先不正确(与黑色节点的属性相矛盾)。因此,无论您是否检查v in Q都没有区别。

在Prim的算法中,可以找到一个小重量的边缘,这导致已经是黑色的顶点。这就是为什么如果我们不检查v in Q,那么顶点v中的值确实会发生变化。通常情况下,没关系,因为我们从未读过黑色顶点的最小权重值。但是,您的伪代码使用MinHeap数据结构。在这种情况下,顶点值的每个修改必须伴随 DecreaseKey 。显然,为黑色顶点调用 DecreaseKey 是无效的,因为它们不在堆中。这就是为什么我认为作者决定明确检查v in Q

一般来说,Dijkstra和Prim算法的代码通常是完全相同的,除了一个小的区别:

  • Prim的算法检查w(u, v)在RELAX中是否小于D(v)
  • Dijkstra的算法检查D(u) + w(u, v)在RELAX中减少D(v)

答案 2 :(得分:0)

看看我个人用C ++编写的Dijkstra和Prim的实现。

它们非常相似,我将Dijkstra修改为Prim。

Dijkstra:

const int INF = INT_MAX / 4;
struct node { int v, w; };
bool operator<(node l, node r){if(l.w==r.w)return l.v>r.v; return l.w> r.w;}

vector<int> Dijkstra(int max_v, int start_v, vector<vector<node>>& adj_list) {
    vector<int> min_dist(max_v + 1, INF);  
    priority_queue<node> q;
    q.push({ start_v, 0 });  
    min_dist[start_v] = 0;   
    while (q.size()) {
        node n = q.top(); q.pop();
        for (auto adj : adj_list[n.v]) {
            if (min_dist[adj.v] > n.w + adj.w) {
                min_dist[adj.v] = n.w + adj.w;
                q.push({ adj.v, adj.w + n.w });
            }
        }
    }
    return min_dist;
}

原始:

struct node { int v, w; };
bool operator<(node l, node r) { return l.w > r.w; }
int MST_Prim(int max_v, int start_v, vector<vector<node>>& adj_list) {
    vector<int> visit(max_v + 1, 0);
    priority_queue<node> q; q.push({ start_v, 0 });
    int sum = 0;  
    while (q.size()) {
        node n = q.top(); q.pop();
        if (visit[n.v]) continue;  
        visit[n.v] = 1;
        sum += n.w;
        for (auto adj : adj_list[n.v]) {
            q.push({ adj.v, adj.w });  
        }
    }
    return sum;
}