在带非负权有向图中,提到求最短路径,Dijkstra算法是必然少不了的。而Dijkstra究竟能够怎样来求出最短路径,为了方便以后回顾,做一个比较。
Dijkstra算法适用于邻接矩阵的图的结构,采取贪心的方法,每次选取当前情况的最优解,逐级递进,以广度优先的模式先找出就近点的最小路径后,再往外扩,并且当发现有比已得结果更优的解的时候就进行修正。但这个算法只能解决某一个顶点到其他所有顶点的最短路径。如果要求另一顶点到其他顶点的最短路径,就需要再用这个算法重复一次。(因为是有向图)
算法的分析过程就不做论述了。
算法的过程描述:
(1)初始化:
假设用arcs矩阵来表示带权有向图,arcs[i][j] 来表示顶点i到j的权值,如果i到j不存在,就赋一个其他值,这里用MAX来表示;
数组final表示已找到从出发点(用户给予)的最短路径的终点的集合,初始用于表示出发点到索引对应的顶点的最短路径是否求出,除出发点外,其他都为false;
数组D来表示从出发点(用户给)到其他点(相当于数组索引对应的点)的最短路径的长度。初值就是出发点那个点在arcs中那一行的权值;
循环
{
(2)求最短路径:
找出当前点到最短到达的下一个点。
(3)修正:
遍历顶点路径数组,如果这个值大于(2)中求出的值加上(2)中点到这个遍历到的点的路径,把值赋过来。
伪代码形式 k: 0->最大顶点数 if D[j]+arcs[j][k] < D[k] 则 D[k]=D[j]+arcs[j][k]
}
#include <iostream>
#define MAX 65535
#define MAXVEX 20
using namespace std;
typedef struct
{
int arcs[MAXVEX][MAXVEX];
int vexnum,arcnum;
}MGraph;
void Dijkstra(MGraph &G,int v0,int* D,int* path)
{
int i,j,k=0; //用于控制循环的变量,K则为编号暂存变量
int final[MAXVEX]; //作为标记数组,用来标记索引对应编号的顶点是否已经获取到最小路径
for(i=0;i<G.vexnum;i++)
{
D[i]=G.arcs[v0][i]; //D数组用来存放初始点到索引对应顶点编号的最短路径长度
final[i] = false;
if(D[i]!= MAX) //初始化。如果初始顶点到其他顶点有权值则指定前驱为初始点
path[i]=v0; // path数组是用来存放索引对应的顶点编号在最短路径中的前驱
else
path[i]=MAX;
}
final[v0]=true;
D[v0] =0;
path[v0]=v0; //以上为初始化也即第(1)部分
for(i=1;i<G.vexnum;i++)
{
int min = MAX;
for(j=0;j<G.vexnum;j++)
if(D[j] < min && final[j] ==0)
{
min = D[j];
k = j;
}
final[k] = true; //找出最短路径,并将编号暂存于k
for(j=0;j<G.vexnum;j++)
{
if(D[j]>min+G.arcs[k][j] &&final[j] ==0)
{
D[j] = min+G.arcs[k][j]; //修正结果,如果还有比这个路径更短的路径,则把更短路径的长度赋值过来
path[j]= k;
}
}
}
}
int main()
{
MGraph myGraph;
int arcs[MAXVEX][MAXVEX] ={0}; //为了方便测试,自己准备了组数据,重心在dijisktra算法,这部分不必在意
arcs[0][2] = 10;
arcs[0][4] = 30;
arcs[0][5] = 100;
arcs[1][2] = 5;
arcs[2][3] = 50;
arcs[3][5] = 10;
arcs[4][3] = 20;
arcs[4][5] = 60;
for(int i =0;i<6;i++)
{
for(int j =0;j<6;j++)
{
if(!arcs[i][j])
arcs[i][j] = MAX;
myGraph.arcs[i][j] = arcs[i][j];
cout<<myGraph.arcs[i][j]<<" ";
}
cout<<endl;
}
myGraph.vexnum = 6;
int *dist = (int*)malloc(60);
int *path = (int*)malloc(60);
Dijkstra(myGraph,0,dist,path);
for(int i =0;i<6;i++)
cout<<dist[i]<<endl;
for(int i=0;i<6;i++)
cout<<path[i]<<endl;
return 0;
}