问题:在一个有向网络中,从某点出发得到所有到该顶点的最短距离。
迪杰斯特拉算法是解单源最短路径问题的一个贪心算法,其基本思想是,设置顶点集合S不断的贪心选择来扩充这个集合。当源点到该顶点的最短距离已知,则添加到集合来,最终包括网络中的所有顶点。
贪心选择:
step1:首先选择网络中的某一顶点V出发,那么该顶点肯定可以添加到S中,然后以V为源点,得到它到其他顶点的距离(初始化d[],表示V到其他顶点的距离)
step2:在这些顶点中选择没有标记过的(即未添加到S集合中的点) 并且到V的距离最小的顶点V’,然后将其标记
step3:更新d[],从V’出发遍历网络没有标记的顶点,如果找到一个点d[u]+edge[u][j]<d[j]的情况,则更新d[j]=d[u]+edge[u][j]
step4:重复step2
性能分析:
算法时间主要花在两个for循环中,时间复杂度为O(n2)
代码实现:
#include<stdio.h>
typedef char VertexType;
typedef int EdgeType;
#define MAX 20//定义数组大小
#define INFINITY 500
typedef struct
{
VertexType vexs[MAX];
EdgeType edges[MAX][MAX];
int vexnum;//记录图的顶点数
int arcnum;//记录图的边或弧的条数
}AdjMatrix;
//创建图的邻接矩阵
AdjMatrix CreatGraph_Matrix(int graphtype)
{
AdjMatrix G;
int i,j,k;
int weight;
printf("please input graph's vexnum and arcnum:\n");
scanf("%d,%d",&G.vexnum,&G.arcnum);
setbuf(stdin,NULL);
for(i=1;i<=G.vexnum;i++)
{
scanf("%c",&G.vexs[i]);
setbuf(stdin,NULL);
}
setbuf(stdin,NULL);
for(i=1;i<=G.vexnum;i++)
for(j=1;j<=G.vexnum;j++)
G.edges[i][j]=INFINITY;
for(k=1;k<=G.arcnum;k++)
{
printf("please input NO.%d edge's start,end and weight:\n",k);
scanf("%d,%d,%d",&i,&j,&weight);
G.edges[i][j]=weight;
}
return G;
}
void Dijkstra(AdjMatrix &N,int v,int D[],int P[])
{
int S[MAX];
int mindistance,temp;
int i,j,u;
/*******开始初始化的工作*******/
for(i=1;i<=N.vexnum;i++)//前提是采取邻接矩阵储存,并且是有向网络
{
D[i]=N.edges[v][i];
S[i]=0;
if(INFINITY==N.edges[v][i])
P[i]=-1;
else
P[i]=v;
}
S[v]=1;
/**********开始最短路径求解************/
for(i=1;i<=N.vexnum;i++)
{
mindistance=INFINITY;
//在D中找出尚未确定最短路径的顶点中路径长度最小的顶点u
for(j=1;j<=N.vexnum;j++)
{
if(0==S[j]&&D[j]<mindistance)
{
mindistance=D[j];
u=j;
}
}
S[u]=1;//找到路径最小的顶点,然后进行标识
//对还未确定最短路径的顶点进行调整
for(j=1;j<=N.vexnum;j++)
{
if(0==S[j])//未确定最短路径的顶点
{
temp=D[u]+N.edges[u][j];
if(D[j]>temp)
{
D[j]=temp;//修改最短路径
P[j]=u;//同时修改前驱
}
}
}
}
}
int main()
{
AdjMatrix G;
G=CreatGraph_Matrix(51);
int D[MAX],P[MAX];
Dijkstra(G,1,D,P);
for(int i=1;i<=G.vexnum;i++)
{
printf("D[%d]=%d,P[%d]=%d\n",i,D[i],i,P[i]);
}
return 0;
}