注意:本算法采用邻接表存储图
一:迪杰斯特拉算法
假如以顶点v1起点,用迪杰斯特拉算法求起点分别到顶点v2,v3,v4,v5的最短路径,初始我们计算出起点到各个顶点的最短路径,然后连接起点到某顶点的最短路径是所有路径中最短的那个顶点(加入到S集),然后接着重复这样的步骤,直到所有顶点都被连接
二.思路分析
1.构建终点标记数组final[v],final[v]=1时表示已经求得起点到顶点v的最短路径,final[v]=0表示未求得顶点v的最短路径
构建路径存储数组P[v][ ], 存储顶点v的最短路径中的顶点w,p[v][w1]=1表示路径中存在顶点w1,p[v][w2]=0表示路径中不存在顶点w2
构建路径权值存储数组D[v],存储起点到顶点v的最短路径的权值
初始化: 我们先计算起点v0到各个的顶点的路径的权值,存入D数组中,并把路径存入P数组中
2.从D数组中到找到最短的路径D[v],使final[v]=1,标记为已找到起点v0到顶点v的最短路径
3.接着遍历以顶点v为弧尾的顶点,检查是否会因为v顶点的连接而导致其他顶点w的路径变短,如果变短了,就更新路径P[w][ ] 和路径权值D[w] (w的路径等于v的路径加上弧v->w,w的路径权值等于v的路径权值加上弧v->w的权值 )
4.就这样重复2,3步骤n次(n=顶点数-1),就找到了起点v0到其他所有顶点的最短路径(存储在P中)
注意:以上v,w,v0,w1,w2都是指顶点在顺序表中的存储位置序号,而非顶点名
三.代码实现
#include"stdio.h"
#include"stdlib.h"
#define MAX_VERTEX_NUM 50 //最大顶点数
#define NOWAY 9999999 //表示没有路径,权值无穷大
typedef int VertexType; //顶点类型(顶点的值)
typedef int VRType; //顶点关系类型(权值)
typedef enum
{
DG,DN,UDG,UDN //{有向图,有向网,无向图,无向网}
}GraphKind; //图类型
typedef struct ArcNode
{
int adjvex; //该弧所指向的顶点的位置(顺序表中的位置)
int weight; //弧的权值(无权值的图用1表示连通,有权值的图就是直接存入权值)
struct ArcNode *nextarc; //指向下一条弧的指针
//InfoType *info; //该弧相关信息的指针
}ArcNode; //弧
typedef struct VNode
{
VertexType data; //顶点信息(顶点的值)
ArcNode *firstarc; //指向第一条依附该顶点弧的指针
}VNode; //顶点
typedef struct
{
VNode vexs[MAX_VERTEX_NUM]; //顶点向量顺序表
int vexnum,arcnum; //图的当前顶点数和弧数
GraphKind kind; //图的种类标志
}ALGraph; //邻接表图
//打印操作
void Print(VertexType &v)
{
printf("%d",v);
}
//搜寻顶点在顺序表中的位置
int LocateVex(ALGraph &G,VertexType v)
{
for(int pos=0;pos<G.vexnum;pos++)
{
if(G.vexs[pos].data==v)
return pos;
}
return 0;
}
//构建有向图
void CreateDG(ALGraph &G)
{
printf("\n请依次输入有向图的顶点数和弧数(空格隔开):\n");
scanf("%d %d",&G.vexnum,&G.arcnum); //输入图的顶点数和弧数
printf("\n请依次输入有向图的顶点向量(空格隔开,最后一个顶点后也要加空格)\n");
for(int pos=0;pos<G.vexnum;pos++)
{
scanf("%d",&G.vexs[pos].data); //输入图的顶点向量
G.vexs[pos].firstarc=NULL; //第一条弧的指针暂时赋为空
}
printf("\n请依次输入有向图的弧的弧头和弧尾顶点与权值(空格隔开,按回车输入下一条边):\n");
VertexType v1,v2; //弧依附的顶点
VRType w; //弧的权值
int head,tail; //弧头和弧尾在顺序表中的位置序号
for(int a=0;a<G.arcnum;a++)
{
scanf("%d %d %d",&v1,&v2,&w); //输入弧的弧头和弧尾顶点与权值
head=LocateVex(G,v1); //找到弧头顶点在顺序表中的位置
tail=LocateVex(G,v2); //找到弧尾顶点在顺序表中的位置
ArcNode *node=(ArcNode*)malloc(sizeof(ArcNode)); //新建弧节点
node->weight=w;
node->adjvex=tail;
node->nextarc=G.vexs[head].firstarc; //用前插法将弧节点插入
G.vexs[head].firstarc=node;
}
}
//用迪杰斯特拉算法求连通图中的某点到所有顶点的最短路径
void ShortestPath_DIJ(ALGraph &G,VertexType SV)
{
//用迪杰斯特拉算法求有向网G的顶点v0到其余顶点v的最短路径P[v]及其带权路径D[v]
//若P[v][w]为1,则w是从v0到v当前求得最短路径上的顶点
//final[v]为1当且仅当v属于S,即已经求得从v0到v的最短路径
int v,w; //弧尾顶点,弧头顶点在顺序表中的位置
bool final[G.vexnum]; //终点标记
int D[G.vexnum]; //起点到某点的路径的权值
int P[G.vexnum][G.vexnum]; //路径存储表
int v0=LocateVex(G,SV); //起点顶点在顺序表中的位置
for(v=0;v<G.vexnum;v++) //数据初始化
{
final[v]=0; //初始没有成为终点
D[v]=NOWAY; //初始路仅还没有连接
for(w=0;w<G.vexnum;w++)
P[v][w]=0; //表示v-w未连接
P[v][v0]=1; //表示v0加入v顶点的路径,起点v0是所有顶点路径中都存在的
}//for v
for(ArcNode *p=G.vexs[v0].firstarc;p!=NULL;p=p->nextarc) //依次遍历以起点为弧尾的顶点,数据初始化
{
w=p->adjvex; //以起点为弧尾的顶点w(在顺序表中的位置序号)
D[w]=p->weight; //求得各顶点到v0的路径权值
P[w][w]=1; //表示w顶点加入w顶点的路径中
}
D[v0]=0; //v0到v0的路径权值为0
final[v0]=1; //初始化,v0顶点属于S集
//开始主循环,每次求得v0到某个顶点v的最短路径,并把v加到s集
for(int i=1;i<G.vexnum;i++) //其余G.vexnum-1个顶点
{
int min=NOWAY; //当前所知离顶点的最近距离
for(w=0;w<G.vexnum;w++)
{
if(!final[w]&&D[w]<min) //w顶点未连接,且离v0顶点更近
{
v=w; //用选择法找到路径最短的连接顶点
min=D[w];
}
}//for w
final[v]=1; //离v0顶点最近的v加入到S集,表示找到v起点到G.vexs[v]顶点的最短路径
//printf("%d ",G.vexs[v].data);
for(ArcNode *p=G.vexs[v].firstarc;p!=NULL;p=p->nextarc) //依次遍历以G.vexs[v]顶点为弧为的顶点,更新当前最短路径及距离
if(!final[p->adjvex]&&(min+p->weight<D[p->adjvex])) //如果起点到某未成为终点的顶点的路径存在更短路径
{
w=p->adjvex; //以V为弧尾的顶点w(在顺序表中的位置序号)
D[w]=min+p->weight; //替换为更短的路径(权值)
for(int j=0;j<G.vexnum;j++)
P[w][j]=P[v][j]; //先复制顶点v的路径
P[w][w]=1; //然后路径中加入顶点w
}//if
}//for i
for(int r=0;r<G.vexnum;r++) //打印路径连接表
{
printf("\n");
for(int c=0;c<G.vexnum;c++)
printf("%d ",P[r][c]);
}
}//ShortestPath_DIJ
int main()
{
ALGraph G1;
printf("\n构建有向图:\n");
CreateDG(G1);
printf("\n起点到各顶点的最短路径连接表:\n");
ShortestPath_DIJ(G1,1);
return 0;
}
操作结果: