(Dijkstra)算法--按路径长度递增序产生各顶点最短路径

迪杰斯特拉(Dijkstra)算法求单源最短路径
 由Dijkstra提出的一种按路径长度递增序产生各顶点最短路径的算法。
(1)按路径长度递增序产生各顶点最短路径 
 若按长度递增的次序生成从源点s到其它顶点的最短路径,则当前正在生成的最短路径上除终点以外,其余顶点的最短路径均已生成(将源点的最短路径看作是已生成的源点到其自身的长度为0的路径)。

 关键字路径长度递增序  这个要理解。

Dijkstra算法举例说明

如下图,设A为源点,求A到其他各顶点(BCDEF)的最短路径。线上所标注为相邻线段之间的距离,即权值。(注:此图为随意所画,其相邻顶点间的距离与图中的目视长度不能一一对等)


《(Dijkstra)算法--按路径长度递增序产生各顶点最短路径》

 

算法执行步骤如下表:【注:图片要是看不到请到相册日志相册中,名为“Dijkstra算法过程的图就是了】

步骤

S集合中

U集合中

1

选入A,此时S=<A>

此时最短路径A→A=0

A为中间点,从A开始找

U=<BCDEF>

A→B=6A→C=3

A→其它U中的顶点=∞

发现A→C=3权值为最短

2

选入C,此时S=<AC>

此时最短路径A→A=0A→C=3C为中间点,

A→C=3这条最短路径开始找

U=<BDEF>

A→C→B=5(比上面第一步的A→B=6要短)

此时到D权值更改为A→C→B=5

A→C→D=6

A→C→E=7

A→C→其它U中的顶点=∞,发现A→C→B=5权值为最短

3

选入B,此时S=<ACB>

此时最短路径A→A=0A→C=3A→C→B=5

B为中间点

A→C→B=5这条最短路径开始找

U=<DEF>

A→C→B→D=10(比上面第二步的A→C→D=6要长)

此时到D权值更改为A→C→D=6

A→C→B→其它U中的顶点=∞,发现A→C→D=6权值为最短

4

选入D,此时S=<ACBD>

此时最短路径A→A=0A→C=3A→C→B=5A→C→D=6

D为中间点,

A→C→D=6这条最短路径开始找

U=<EF>

A→C→D→E=8(比上面第二步的A→C→E=7要长)此时到E权值更改为A→C→E=7A→C→D→F=9

发现A→C→E=7权值为最短

5

选入E,此时S=<ACBDE>

此时最短路径A→A=0A→C=3A→C→B=5A→C→D=6A→C→E=7,以E为中间点,

A→C→E=7这条最短路径开始找

U=<F>

A→C→E→F=12(比上面第四步的A→C→D→F=9要长)此时到F权值更改为A→C→D→F=9

发现A→C→D→F=9权值为最短

6

选入F,此时S=<ACBDEF>

此时最短路径A→A=0A→C=3

A→C→B=5

A→C→D=6

A→C→E=7A→C→D→F=9

U集合已空,查找完毕。

(2)算法基本思想

算法基本思想

 设S为最短距离已确定的顶点集(看作红点集),V-S是最短距离尚未确定的顶点集(看作蓝点集)。

①初始化

 初始化时,只有源点s的最短距离是已知的(SD(s)=0),故红点集S={s},蓝点集为空。

②重复以下工作,按路径长度递增次序产生各顶点最短路径

 在当前蓝点集中选择一个最短距离最小的蓝点来扩充红点集,以保证算法按路径长度递增的次序产生各顶点的最短路径。

 当蓝点集中仅剩下最短距离为∞的蓝点,或者所有蓝点已扩充到红点集时,s到所有顶点的最短路径就求出来了。

注意:

 ①若从源点到蓝点的路径不存在,则可假设该蓝点的最短路径是一条长度为无穷大的虚拟路径。

 ②从源点s到终点v的最短路径简称为v的最短路径;s到v的最短路径长度简称为v的最短距离,并记为SD(v)。


(3)在蓝点集中选择一个最短距离最小的蓝点k来扩充红点集

 根据按长度递增序产生最短路径的思想,当前最短距离最小的蓝点k的最短路径是:

 源点,红点1,红点2,…,红点n,蓝点k

距离为:源点到红点n最短距离+<红点n,蓝点k>边长

 为求解方便,设置一个向量D[0..n-1],对于每个蓝点v∈ V-S,用D[v]记录从源点s到达v且除v外中间不经过任何蓝点(若有中间点,则必为红点)的”最短”路径长度(简称估计距离)。

 若k是蓝点集中估计距离最小的顶点,则k的估计距离就是最短距离,即若D[k]=min{D[i] i∈V-S},则D[k]=SD(k)。

 初始时,每个蓝点v的D[c]值应为权w<s,v>,且从s到v的路径上没有中间点,因为该路径仅含一条边<s,v>。

注意:

 在蓝点集中选择一个最短距离最小的蓝点k来扩充红点集是Dijkstra算法的关键


(4)k扩充红点集s后,蓝点集估计距离的修改

 将k扩充到红点后,剩余蓝点集的估计距离可能由于增加了新红点k而减小,此时必须调整相应蓝点的估计距离。

 对于任意的蓝点j,若k由蓝变红后使D[j]变小,则必定是由于存在一条从s到j且包含新红点k的更短路径:P=<s,…,k,j>。且D[j]减小的新路径P只可能是由于路径<s,…,k>和边<k,j>组成。

 所以,当length(P)=D[k]+w<k,j>小于D[j]时,应该用P的长度来修改D[j]的值。

(5)Dijkstra算法

Dijkstra(G,D,s){

//用Dijkstra算法求有向网G的源点s到各顶点的最短路径长度

//以下是初始化操作

S={s};D[s]=0; //设置初始的红点集及最短距离

for( all i∈ V-S )do //对蓝点集中每个顶点i

D[i]=G[s][i]; //设置i初始的估计距离为w<s,i>

//以下是扩充红点集

for(i=0;i<n-1;i++)do{//最多扩充n-1个蓝点到红点集

D[k]=min{D[i]:all i V-S}; //在当前蓝点集中选估计距离最小的顶点k

if(D[k]等于∞)

return; //蓝点集中所有蓝点的估计距离均为∞时,

//表示这些顶点的最短路径不存在。

S=S∪{k}; //将蓝点k涂红后扩充到红点集

for( all j∈V-S )do //调整剩余蓝点的估计距离

if(D[j]>D[k]+G[k][j])

//新红点k使原D[j]值变小时,用新路径的长度修改D[j],

//使j离s更近。

D[j]=D[k]+G[k][j];

}

}

6)具体实现

void Dijkstra(MGraph *G,int s)
{
    //用Dijkstra算法求有向网G的源点s到各顶点的最短路径长度

int S[G->n];              //辅助数组用来标志顶点是否已经在最短路径的顶点集合中
int Dist[G->n];          //到源点的距离
int i,j,u;
int MinDist;
for(i=0;i<G->n;i++)    //初始化各数组
 {
S[i]=0;
Dist[i]=G->edges[s][i];//设置i初始的估计距离为w<s,i> //距离初始化
 }
S[s]=1;                             //顶点s加入到集合s中
for(i=0;i<G->n-1;i++)
{              //将最短路径顶点加入到s中
  MinDist=INFINITE;
u=-1;
for(j=0;j<G->n;j++)             //找当前的最短路径
{
if(S[j]==0 && Dist[j]<MinDist)
{
u=j;
MinDist=Dist[j];
}
}
S[u]=1;                          //j顶点加入到s中
for( j=0;j<G->n;j++)          //根据顶点调整当前的最短路径
{
if(S[j]==0&&Dist[u]+G->edges[u][j]<Dist[j])
{
 Dist[j]=Dist[u]+G->edges[u][j];
}
}
}
for(j=0;j<G->n;j++)
{
  if(Dist[j]==INFINITE)
{
printf(“%d到%d的无路径 \n”,s,j);
}
 else
     printf(“%d到%d的最短距离是%d \n”,s,j,Dist[j]);
}
}

7) 最短路径的打印与求两点间的最短路径

void PrintPath(int path[],int i,int v0)//打印v0到顶点i的路径
{
int k;
k=path[i];
if(k==v0)
return;
PrintPath(path,k,v0);
printf(“%d–>”,k);
}

void Dijkstra(MGraph *G,int s)
{
    //用Dijkstra算法求有向网G的源点s到各顶点的最短路径长度

int S[G->n];              //辅助数组用来标志顶点是否已经在最短路径的顶点集合中
int Dist[G->n];          //到源点的距离
int Path[G->n];    //存放路径,注意这里的路径信息表示什么意思?Path[i]表示源点s到达顶点i的最短路径中的最后一个顶点j(i!=j)
//例如顶点0到顶点2的路径为0–>1–>3–>2 即Path[2]=3,那么从0到顶点3的路径的最后一个顶点是什么呢,这时可以看Path[3];很显然Path[3]==1
int i,j,u;
int MinDist;
for(i=0;i<G->n;i++)    //初始化各数组
 {
S[i]=0;
Dist[i]=G->edges[s][i];//设置i初始的估计距离为w<s,i> //距离初始化
if(G->edges[s][i]<INFINITE)
{
Path[i]=s;       //路径初始化
}
else
Path[i]=-1;       //不能用0表示,0表示顶点序号0
 }
S[s]=1;                             //顶点s加入到集合s中
Path[s]=0;
for(i=0;i<G->n-1;i++)
{              //将最短路径顶点加入到s中
  MinDist=INFINITE;
u=-1;
for(j=0;j<G->n;j++)             //找当前的最短路径
{
if(S[j]==0 && Dist[j]<MinDist)
{
u=j;
MinDist=Dist[j];
}
}
S[u]=1;                          //j顶点加入到s中
for( j=0;j<G->n;j++)          //根据顶点调整当前的最短路径
{
if(S[j]==0&&Dist[u]+G->edges[u][j]<Dist[j])
{
 Dist[j]=Dist[u]+G->edges[u][j];
 Path[j] = u;//保存路径
}
}
}
printf(“输出最短路径:\n”);
for(i=0;i<G->n;i++)//用于输出最短路径和路径长度
{
  if(Dist[i]==INFINITE||i==s)
{
printf(“从%d到%d不存在路径\n”,s,i);
}
  else if(S[i]==1&&i!=s)
{   printf(“从%d到%d的最短距离为:%d\t”,s,i,Dist[i]);
printf(“最短路径为:”);
printf(“%d–>”,s);
PrintPath(Path,i,s); //打印s到顶点i的路径
printf(“%d\n”,i);
}
}
}

8)Floyd算法 计算图的任意两点间的最短路径

这个算法较简单,特别容易记住和使用,就是效率较低。

void PrintPath(int path[],int i,int v0)//打印v0到顶点i的路径
{
//存放路径,注意这里的路径信息表示什么意思?Path[i]表示源点s到达顶点i的最短路径中的最后一个顶点j(i!=j)
//例如顶点0到顶点2的路径为0–>1–>3–>2 即Path[2]=3,那么从0到顶点3的路径的最后一个顶点是什么呢,这时可以看Path[3];很显然Path[3]==1
//所以打印路径可以用递归方法打印直到Path[k]=k时停止
int k;
k=path[i];
if(k==v0)
return;
PrintPath(path,k,v0);
printf(“%d–>”,k);
}
//FLOYD算法 求任意两点最短路径矩阵
void floyd(MGraph *G , int s, int d ) //FLOYD算法 计算矩阵表示的图的任意两点的距离和路径
{
int Dist[G->n][G->n];
int Path[G->n][G->n];
int i,j;
// 先初始化_arrPath
for (  i = 0; i < G->n; ++i )
{
  for (  j = 0; j <G->n; ++j )
 {
 Path[i][j] = i;
  }
}
// 先初始化Dis
for (  i = 0; i < G->n; ++i )
{
for (  j = 0; j < G->n; ++j )
 {
    Dist[i][j] = G->edges[i][j];
}
}
//FLOYD算法 计算所以最短路径的矩阵信息
for ( int k = 0; k < G->n; ++k )
   {
       for (  i = 0; i < G->n; ++i )
       {
           for ( j = 0; j < G->n; ++j )
           {
               if ( Dist[i][k] + Dist[k][j] < Dist[i][j] )
               {      // 找到更短路径
                   Dist[i][j] = Dist[i][k] + Dist[k][j];
                   Path[i][j] = Path[k][j];//保存路径
               }
           }
       }
   }
printf(“从%d到%d的最短距离为:%d\t”,s,d,Dist[s][d]);
printf(“最短路径为:”);
printf(“%d–>”,s);
PrintPath(Path[s],d,s); //打印s到顶点d的路径
printf(“%d\n”,d);
}

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/abilly/article/details/23133509
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞