C++中的Dijkstra算法

Dijkstra's algorithm in C++

本文关键字:算法 Dijkstra 中的 C++      更新时间:2023-10-16

我需要通过ADT图实现Dijkstra的算法,使用邻接矩阵表示,通过使用C/c++语言增强下面的伪代码来寻找最短路径。

procedure Dijkstra(G, w, r, Parent[0:n-1], Dist)
  for v← 0 to n-1 do
    Dist[v] ← ∞
    InTheTree[v] ← .false.
  endfor
  Parent[r] ←-1
  Dist[r] ←0
  for Stage ←1 to n-1 do 
    Select vertex u that minimises Dist[u] over all u such that InTheTree[u] = .false. 
    InTheTree[u] = .true.                                       // add u to T
    for each vertex v such that uv ∈ E do             // update Dist[v] and 
      if .not. InTheTree[v]  then                // Parent[v] arrays
        if Dist[u] + w(uv) < Dist[v]
          Dist[v] = Dist[u] + w(uv)
          Nearest[v] ←w(uv) 
          Parent[v] ← u
        endif
      endif
    endfor
  endfor
end Dijkstra

这是我的代码的解决方案,正在用c++编码。我的讲师声称代码不符合伪代码的要求,我不确定哪里出了问题,谁能帮我找出代码和伪代码之间不匹配的地方?

#include <stdio.h>
#include <limits.h>
#define N 9
int minDistance(int dist[], bool sptSet[])
{
   int min = INT_MAX, min_index;
   for (int n = 0; n < N; n++)
     if (sptSet[v] == false && dist[n] <= min)
         min = dist[n], min_index = n;
   return min_index;
}
int printSolution(int dist[], int v)
{
   printf("Vertex   Distance from Sourcen");
   for (int i = 0; i < N; i++)
      printf("%d tt %dn", i, dist[i]);
}
void dijkstra(int graph[N][N], int src)
{
     int dist[N];     
     bool sptSet[N];                         
     for (int i = 0; i < N; i++) {
        dist[i] = INT_MAX;
        sptSet[i] = false;
     }
     dist[src] = 0;

     for (int count = 0; count < N-1; count++)
     {
       int u = minDistance(dist, sptSet);
            sptSet[u] = true;
       for (int n = 0; n < N; n++)
         if (!sptSet[n] && graph[u][n] && dist[u] != INT_MAX 
                                       && dist[u]+graph[u][n] < dist[n])
            dist[n] = dist[u] + graph[u][n];
     }
     printSolution(dist, N);
}
int main()
{
   int graph[N][N] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},
                      {4, 0, 8, 0, 0, 0, 0, 11, 0},
                      {0, 8, 0, 7, 0, 4, 0, 0, 2},
                      {0, 0, 7, 0, 9, 14, 0, 0, 0},
                      {0, 0, 0, 9, 0, 10, 0, 0, 0},
                      {0, 0, 4, 0, 10, 0, 2, 0, 0},
                      {0, 0, 0, 14, 0, 2, 0, 1, 6},
                      {8, 11, 0, 0, 0, 0, 1, 0, 7},
                      {0, 0, 2, 0, 0, 0, 6, 7, 0}
                     };
    dijkstra(graph, 0);
    return 0;
}

最明显的不匹配是您的代码没有任何与伪代码的Parent数组相对应的内容。我把它作为一个输出参数,尽管它没有明确地这样标记。正如你似乎已经认识到的,它不需要只计算最小路径的长度,但它包含了这些路径中实际步骤的所有信息,而这些信息通常是需要的。

你也没有伪代码的Nearest的类比;但是,抱怨这一点有点意味,因为Nearest不是例程的参数,并且伪代码没有显示其元素被读取。因此,它似乎没有任何有用的目的。

似乎这段代码也不完全匹配:

         if (!sptSet[n] && graph[u][n] && dist[u] != INT_MAX 
                                       && dist[u]+graph[u][n] < dist[n])
            dist[n] = dist[u] + graph[u][n];

条件&& dist[u] != INT_MAX不对应于伪代码中的任何内容。(这也是不必要的,因为u是由minDistance()返回的,因此该条件应该总是满足的)。

可以想象,您的指导老师也可能不满意您打印最小路径长度而不是返回它们。它有点依赖于伪代码方言,但我倾向于把参数列表中Dist的出现作为它是一个输出参数的指示,而不仅仅是一个内部变量。

如果你的老师非常挑剔,那么也许你可以通过指出伪代码中一些明显的错误来得到一些松懈:

    如前所述,Nearest不是一个参数,它被写入,但从不从中读取。
  • 看起来条件if Dist[u] ← w(uv) < Dist[v] then应该改为if Dist[u] + w(uv) < Dist[v] then。(您已经实现了正确的版本,这可能被解释为与伪代码的另一个差异。)
  • 看起来Parent[r] ← u应该是Parent[v] ← u

当然,也可能是你的导师希望你准确地实现伪代码,错误和所有....

作为策略问题,我会尝试使用更好地匹配伪代码的变量名。我不认为老师以这些理由拒绝这些代码是公平的,但是比较c++代码和伪代码对于每个人来说会更容易一些,如果你能更接近你的名字的话。

当我在谈论你的代码时,顺便说一下,我注意到虽然你的minDistance()函数似乎实现了伪代码的需求,但它是以一种低效的方式实现的(而且Dijkstra一开始就不是特别高效)。通常的方法是使用最小堆来跟踪已经看到但尚未访问的节点,这减少了从O(n)到O(log n)选择最小距离节点的成本。当然,对于您正在测试的元素很少,这并不重要,但对于大型图,差异是巨大的。

问题是我相信你的minDistance函数,似乎你只更新未访问的节点(第10行如果(sptSet[v] == false &&Dist [n] <= min))。我想这是错的。考虑下面的图(节点V={n1, n2, n3, n4},距离d(n1, n2) = 10;D (n1,n3) = 3;D (n3,n2) = 3(其他都是无穷大)

从n1开始你发现n2的代价是10

你以3的代价发现了n3

从n2你没有发现到n2 (n1-n3-n2)的更短的路径,因为你已经把n2标记为访问过。

我不确定,如果我是对的。