Dijkstra算法-求单源最短路径
算法演示:
假设一个无向连通图如图所示,算法的重要作用是求单点到各点的最短距离,因此第一步是要找一个起始点,找这个点到各个点的最短距离,这里我们假设D点作为这个起始点。
同时这个算法需要两个集合,集合S代表已计算出最短路径的定点集合,集合U是未计算出最短路径的集合。为了使U中的元素不断转化未S中的元素,需要不断“激活”图中的点,来保证算法能够正常实现。
这个图中有7个点,因此需要依次激活这7个点。
首先选取D点作为起始点,S集合和U集合如下。
第一步:找到顶点D
S={ D(0) } ; U={ A(∞),B(∞),C(3),E(4),F(∞),G(∞) };
与D连通的只有C和E,所以只有这两个点的路径有具体数值,其余4个点的都未与D直接相连,因此将它们之间的距离用∞表示。
这里注意,U集合中路径最小的是哪个点,下一次就激活哪个点,并把这个点放到S集合中。
因此下一次要激活点C。
第二步:激活顶点C
S={ D(0),C(3)}; U={ A(∞) , B(13) , E(4) , F(9) , F(∞)};
由红体字所得,将C点放入S集合中,但同时要注意原来的路径长度是否要更新,如果新路径的长度比原路径小,就将路径更新。
在这个U集合当中,E的路径最短,因此下一步要激活顶点E。
第三步:激活顶点E
S={ D( 0 ),C( 3 ),E( 4 )}: U={A(∞) , B(13) , F(6) , G(12)};
这里E就作为已经计算好的最短路径放在S中,这里值得注意的是,当E点吧被激活后,从F点到D点可以通过E点,同时通过E点的这条路径要比原来的短,因此要把它更新,F的最短路径变为6,G的最短路径变为12。
在这个U集合当中,F的路径最短,因此下一步要激活顶点F。
第四步:激活顶点F
S={D(0) , C(3) , E(4) , F(6)}; U={A(22) , B(13) , G(12)};
当F点被激活以后,A,B,G均可以通过F与D相连接,因此A,B,G的最短路径都要被更新。
在这个U集合当中,G的路径最短,因此下一步要激活顶点G。
第五步:激活顶点G
S={D(0) , C(3) , E(4) , F(6),, G(12)}; U={A(22) , B(13) };
当G点被激活后,A,B的路径都没有变得更短,因此不需要更新。
在这个U集合当中,B的路径最短,因此下一步要激活顶点B。
第六步:激活顶点B
S={D(0) , C(3) , E(4) , F(6),, G(12),, B(13) }; U={A(22) };
当B点被激活后,A的路径并没有变得更短,因此不需要更新。
下一步激活顶点A。
第七步:激活顶点A
S={D(0) , C(3) , E(4) , F(6),, G(12),, B(13),A(22) }; U={};
至此,寻取单源最短路径算法演示已完成,下面是代码实现。
代码及解释如下:
#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
using namespace std;
#define row 7
#define col 7
#define inf 0x3f3f3f3f
//用二维数组将图表示出来
int matrix[row][col] = {
{inf,12,inf,inf,inf,16,14},
{12,inf,10,inf,inf,7,inf},
{inf,10,inf,3,5,6,inf},
{inf,inf,3,inf,4,inf,inf},
{inf,inf,5,4,inf,2,8},
{16,7,6,inf,2,inf,9},
{14,inf,inf,inf,8,9,inf}
};
//vis代表标记数组,s是已经计算出最短路径的集合数组
//u是未计算出最短路径的集合数组
//nextnode代表记录它的下一个节点
int vis[7], s[7], u[7], nextnode[7];
void Dijkstra(int index)
{
vis[index] = 1;//D点先标记(为了防止D再被放到U集合中)
for (int i = 0; i < 7; i++)
u[i] = matrix[index][i];//先将以D点为起点的U集合初始化
int min_cur = index;
int Count = 6;//只需要再激活6个点即可
while (Count)
{
int minx = inf;
//第一次遍历U集合,目的是找到U集合中的最短路径的点
//并在循环结束后将其放到S集合中
for (int i = 0; i < 7; i++)
{
if (!vis[i] && u[i]<minx)//寻找U集合最短的路径
{
minx = u[i];//将最小值更新
min_cur = i;//把最小值的下标记录下来,要知道激活了哪个点
}
}
s[min_cur] = minx;//放入最短路径的S集合中相应位置
vis[min_cur] = 1;//将激活过的点标记
//第二次遍历U集合,目的是看U集合中的剩下点的路径能否更新成更短的
//因为激活的点有可能与其他的点连接起来,距离一定比inf小,就可以更新
for (int i = 0; i < 7; i++)
{
//如果激活的点与剩余未被标记过的点的距离仍然是inf,则不变
//如果不是inf则把路径计算并记录下来
//并在下一个if语句中判断是否比原来的短
int tmp=matrix[i][min_cur] == inf ? inf : minx + matrix[i][min_cur];
if (!vis[i] && tmp < u[i])
{
u[i] = tmp;//比它短就更新
nextnode[i] = min_cur;
}
}
Count--;
}
}
int main()
{
for (int i = 0; i < 7; i++)
nextnode[i] = -1;
Dijkstra('D' - 'A');//D点作为起点
for (int i = 0; i < 7; i++)//显示最短距离
{
cout << "D到" << char(i + 'A') << "的最短距离是" << s[i] << endl;
}
int index = 0;
while (index != -1)
{
cout << char(index + 'A');
index = nextnode[index];
}
cout << "D" << endl;
return 0;
}