(七)1.2_迪杰斯特拉算法求最短路径

注意:本算法采用邻接表存储图

一:迪杰斯特拉算法

(七)1.2_迪杰斯特拉算法求最短路径_第1张图片
  假如以顶点v1起点,用迪杰斯特拉算法求起点分别到顶点v2,v3,v4,v5的最短路径,初始我们计算出起点到各个顶点的最短路径,然后连接起点到某顶点的最短路径是所有路径中最短的那个顶点(加入到S集),然后接着重复这样的步骤,直到所有顶点都被连接
(七)1.2_迪杰斯特拉算法求最短路径_第2张图片


二.思路分析

  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;
}

操作结果:
(七)1.2_迪杰斯特拉算法求最短路径_第3张图片

你可能感兴趣的:(数据结构(C语言版))