Dijkstra算法:
首先,引进一个辅助向量D,它的每个分量D[i]表示当前所找到的从始点v到每个终点vi的的长度:如D[3]=2表示从始点v到终点3的路径相对最小长度为2。这里强调相对就是说在算法过程中D的值是在不断逼近最终结果但在过程中不一定就等于长度。它的初始状态为:若从v到vi有弧,则D为弧上的权值;否则置D为∞。显然,长度为 D[j]=Min{D | vi∈V} 的路径就是从v出发的长度最短的一条。此路径为(v,vj)。 那么,下一条长度次短的是哪一条呢?假设该次短路径的终点是vk,则可想而知,这条路径或者是(v,vk),或者是(v,vj,vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的弧上的权值之和。 一般情况下,假设S为已求得的终点的集合,则可证明:下一条最短路径(设其终点为X)或者是弧(v,x),或者是中间只经过S中的顶点而最后到达顶点X的路径。因此,下一条长度次短的的长度必是D[j]=Min{D | vi∈V-S} 其中,D或者是弧(v,vi)上的权值,或者是D[k](vk∈S)和弧(vk,vi)上的权值之和。
算法描述如下:
1)arcs表示弧上的权值。若不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到从v出发的的终点的集合,初始状态为空集。那么,从v出发到图上其余各顶点vi可能达到的度的初值为D=arcs[Locate Vex(G,v),i] vi∈V
2)选择vj,使得D[j]=Min{D | vi∈V-S} 3)修改从v出发到集合V-S上任一顶点vk可达的最短路径长度。
考虑如下无向网(假设从v0出发):
最短路径数组变化情况:
最初,v0能到达的点为v2,v4,v5,距离分别为10,30,100,到其余点的距离默认为无穷大(max),
然后,取最小权10,纳入S集,即v2点。又v2可以到达v3,距离为50。则v0->v3的距离可为10+50=60,小于当前的值(max),故更新辅助数组。紧接着,再取出一个最小权30(去掉之前的10),即v4,又v4可以到达v3,v5,距离分别为20,60,则v0->v3,v0->v5的距离可以分别为30+20=50,30+60=90,小于目前的值60,100,故而继续更新辅助数组。以此类推,最终得到一个最短路径数组。
实现:
/**************************************
迪杰斯特拉算法求最短路径
by Rowandjj
2014/7/10
**************************************/
#include<iostream>
using namespace std;
#define INFINTY 65535
#define MAX_INFO 20
#define MAX_VERTEX_NUM 20
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];
typedef struct _ARC_
{
int adj;//顶点关系类型
char *info;
}AdiMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct _GRAPH_//图的邻接矩阵存储形式
{
char vexs[MAX_VERTEX_NUM];
AdiMatrix arcs;
int arcnum,vexnum;
}Graph;
//-----------------------
int LocateVex(Graph G,char u);
void CreateDN(Graph *G);
void Display(Graph G);
void ShortestPath_DIJ(Graph G,int v0,PathMatrix *P,ShortPathTable *D);
//---------------------------------------------
int main()
{
Graph g;
CreateDN(&g);
Display(g);
PathMatrix p;
ShortPathTable d;
ShortestPath_DIJ(g,0,&p,&d);
int i,j;
printf("最短路径数组p[i][j]如下:\n");
for(i=0;i<g.vexnum;++i)
{
for(j=0;j<g.vexnum;++j)
cout<<p[i][j]<<"\t";
cout<<endl;
}
cout<<"到各顶点的最短路径长度为:"<<endl;
for(i=1;i<g.vexnum;++i)
cout<<g.vexs[0]<<"-->"<<g.vexs[i]<<":"<<d[i]<<endl;
return 0;
}
//--------------------------------------------
int LocateVex(Graph G,char u)
{
int i = 0;
for(i = 0; i < G.vexnum;i++)
{
if(u == G.vexs[i])
{
return i;
}
}
return -1;
}
void CreateDN(Graph *G)//构建有向网
{
int incInfo;
int i,j,k,l,w;
char s[MAX_INFO];
cout<<"请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0)"<<endl;
cin>>G->vexnum;
cin>>G->arcnum;
cin>>incInfo;
char va,vb;//分别代表弧头、弧尾
char *pInfo;
cout<<"请输入顶点值"<<endl;
for(i = 0; i < G->vexnum; i++)
{
cin>>G->vexs[i];
}
for(i = 0; i < G->vexnum; i++)
{
for(j = 0; j < G->vexnum; j++)
{
G->arcs[i][j].adj = INFINTY;//网
G->arcs[i][j].info = NULL;
}
}
cout<<"请输入弧尾、弧头、权值"<<endl;
for(k = 0; k < G->arcnum; k++)
{
cin>>va;
cin>>vb;
cin>>w;
i = LocateVex(*G,va);
j = LocateVex(*G,vb);
G->arcs[i][j].adj = w;
if(incInfo)
{
cout<<"请输入该弧的信息"<<endl;
cin>>s;
l = strlen(s);
if(l)
{
pInfo = (char *)malloc(sizeof(char)*(l+1));
strcpy(pInfo,s);
G->arcs[i][j].info = pInfo;
}
}
}
}
void Display(Graph G)
{
int i,j;
for(i = 0; i < G.vexnum; i++)
{
for(j = 0; j < G.vexnum; j++)
{
cout<<G.arcs[i][j].adj<<"\t";
}
cout<<endl;
}
cout<<endl;
}
void ShortestPath_DIJ(Graph G,int v0,PathMatrix *P,ShortPathTable *D)
{
int v,w,i,j,min;
int final[MAX_VERTEX_NUM];
for(v=0;v<G.vexnum;++v)
{
final[v]=0;
(*D)[v]=G.arcs[v0][v].adj;
for(w=0;w<G.vexnum;++w)
(*P)[v][w]=0; /* 设空路径 */
if((*D)[v]<INFINTY)
{
(*P)[v][v0]=1;
(*P)[v][v]=1;
}
}
(*D)[v0]=0;
final[v0]=1; /* 初始化,v0顶点属于S集 */
for(i=1;i<G.vexnum;++i) /* 其余G.vexnum-1个顶点 */
{ /* 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */
min=INFINTY; /* 当前所知离v0顶点的最近距离 */
for(w=0;w<G.vexnum;++w)
{
if(!final[w]) /* w顶点在V-S中 */
{
if((*D)[w]<min)
{
v=w;
min=(*D)[w];
} /* w顶点离v0顶点更近 */
}
}
final[v]=1; /* 离v0顶点最近的v加入S集 */
for(w=0;w<G.vexnum;++w) /* 更新当前最短路径及距离 */
{
if(!final[w]&&min<INFINTY&&G.arcs[v][w].adj<INFINTY&&(min+G.arcs[v][w].adj<(*D)[w]))
{ /* 修改D[w]和P[w],w∈V-S */
(*D)[w]=min+G.arcs[v][w].adj;
for(j=0;j<G.vexnum;++j)
(*P)[w][j]=(*P)[v][j];
(*P)[w][w]=1;
}
}
}
}
测试: