迪杰斯特拉算法之生活中的最短路径问题求解原理

最短路径算法在生活中有极其重要的意义与运用,如高铁、地铁的路线规划问题,最近学习了迪杰斯特拉算法,颇有感慨,遂成一篇笔记以记之。
以邻接矩阵为存储结构,如下图所示:
在这里插入图片描述
拓扑结构图如下:在这里插入图片描述

求v0到v8的最短路径,其实思想比较简单,蕴含着贪心法的思想,它并不是一下子求出v0到v8的最短路径,而是先求出v0到v1的最短路径,再求出v2到v3的最短路径,过程就是基于已经求出的最短路径的基础上,求出更远拓扑点的最短路径,最终得出结果;

初始时d,p,final数组的值如下:
d: 0 1 5 65535 65535 65535 65535 65535 65535
p: 0 0 0 0 0 0 0 0 0
final: 1 0 0 0 0 0 0 0 0

代码如下:

#define MAXVEX 9
#define INFINITY 65535 //定义两个宏,主要是便于以后修改数据

typedef int Patharc[MAXVEX];//用于存储最短路径下标的数组
typedef int ShortPathTable[MAXVEX];//用于存储到各点的最短路径权值之和 

void shortpath_dj(Mgraph g,int v0,Patharc *p,ShortPathTable *d)
{
  int v,w,k,min;
  int final[MAXVEX];//final[w]表示已经求得顶点V0到Vw的最短路径,其实就是一个标记数组;
  
//初始化数据
for(v=0;v<.num;v++)
  {
    final[v]=0;  //全部顶点初始化为未找到最短路径;
    (*d)[v]=g.arc[v0][v];  //将和v0点有连线的顶点加上权值;这时初始化完成之后*d指向的数组内容即为邻接表的第一行内容,图中的无穷大全部用65535替代;
    (*p)[v]=0;    //初始化路径数组p为0;
  }
  (*d)[v0]=0;  //v0到v0的的路径为0;
  final[v0]=1; //v0到v0不需要求路径;

//开始主循环,每次求出v0到某一个顶点的最短路径;
for(v=1;v<g.num;v++)
  {
    min=INFINITY;
    for(w=0;w<g.num;w++)
      {
        if(!final[w]&&(*d)[w]<min)
          {
            k=w;
            min=(*d)[w];
          }
      }
      final[k]=1; //表示目前找到的最近顶点下标所对应的内容置1,即代表找到了v0到该点的最短路径;
 }

//修正当前的最短路径以及距离;
for(w=0;w<g.num;w++)
  {
    //如果经过v顶点的路径比现在这条路径的长度短时,就将其覆盖;
    if(!final[w]&&(min+g.arc[k][w]<(*d)[w]))
      {
        (*d)[w]=min+g.arc[k][w];  //修改当前路径的长度,其实(*d)就是一个临时数组,用来不断去更好地取值,这也是贪心法的表现,也可以说这个数组喜新厌旧哈;
        (*p)[w]=k;   //*p你也可以理解为是用来存放前驱结点的数组,具有双重含义,就像现实生活中人们说话有时也有两层意思差不多。比如(*p)[2]内容为1,就表示v2顶点的前驱是v1!
      }
  }


}

每次循环之后,三个数组的值都会相应的变化,最终d,p,final三个辅助数组的值如下,大家可以顺着程序推演一下,很容易就可以推出,也将很好的理解dj算法原理:
d: 0 1 4 7 5 8 10 12 16
p: 0 0 1 4 2 4 3 6 7
final: 1 1 1 1 1 1 1 1 1

看似复杂的算法也就是通过一步步的组合而成,仔细分析就可得其精髓。

发布了8 篇原创文章 · 获赞 8 · 访问量 923

猜你喜欢

转载自blog.csdn.net/weixin_44225901/article/details/104327097