最短路径 迪杰斯特拉算法(Dijkstra)

超详解析,手打不易,转载注明出处,点赞收藏,多谢支持


存储方式 :邻接表

有两个集合

  • S :已得出与V(起始点)最短路径的顶点结合
  • U :S的反集,初始时,所有顶点都在此集合

三个辅助数组:

  1. S[K]: 标记 k 顶点与V(起始点)是否连通
  2. Path[K] : 标记顶点 K 的前驱顶点
  3. Dist[K] : 标记 V 到顶点 K 的最短路径(权值)

算法步骤:

  1. 初始化:将V加入S集合中,并求出与V直接相连的各顶点权值,将这些与V相连的顶点前驱设为V顶点
  2. 循环遍历所有顶点,找到还没确定最短路径,且Dist 最小的顶点K,令S[K]=ture。 并检查所
    有邻接自K的顶点,对于邻接自K的顶点X,若S[X]==false 且 Dist[K] + K到X的权值 < Dist[X],则Dist[X] = Dist[K] + K到X的权值

结果演示
在这里插入图片描述

有向图,C++实现

#include<iostream>
using namespace std;

#define MVNum 100			//最大顶点数 
#define MaxWeight 32425		//最大权值 

typedef char VerTexType; 	//顶点的数据类型为char

typedef struct ArcNode{		//边结点 
	int adjVex;					//该点所指向的顶点位置
	struct ArcNode *nextArc;	//指向下一条边结点的指针
	int info;					//和边相关的信息:可用于带权图 
}ArcNode;
 
typedef struct VNode{		//顶点信息 
	VerTexType data;
	ArcNode *firstArc;		//指向第一条依附该节点的边的指针 
}VNode,AdjList[MVNum];		//AdjList:表示邻接表类型

typedef struct{
	AdjList vertices;			//顶点表 
	int vexnum,arcnum;			//图的当前点数和边数 
}ALGraph;

void CoutResult(ALGraph,int,bool[],int[],int[]);	//输出结果

/*根据顶点名 定位在vertices表中的数组下标*/
int LocateVex(ALGraph G,char v){
	for(int i=0;i<G.vexnum;i++){
		if(G.vertices[i].data == v)
			return i;
	}
	return -1;
} 

/*采用邻接表表示法,创建无向图G*/
bool CreateUDG(ALGraph &G){
	cout << "输入总顶点数、总边数:" << endl; 
	cin >> G.vexnum >> G.arcnum;		//输入总顶点数、总边数
	for(int i=0;i<G.vexnum;i++){
		cin >> G.vertices[i].data;
		G.vertices[i].firstArc = NULL;
	}
	cout << "请输入相互连接的v1、v2、权值:" << endl; 
 	char v1,v2;		//顶点v1、v2 
 	int w,k,j;			//w表示v1-v2的权值 
	for(int i=0;i<G.arcnum;i++){
		cin >> v1 >> v2 >> w;
		k = LocateVex(G,v1);
		j = LocateVex(G,v2);
		/*头插法,给顶点i的第一条边赋值*/
		ArcNode *p1 = new ArcNode;	
		p1->info = w;
		p1->adjVex = j;							//邻接点序号为j 
		p1->nextArc = G.vertices[k].firstArc;	//将新结点p1插入顶点vi的边表头部 
		G.vertices[k].firstArc = p1;
	}
	return true;	 
} 

/*获取两点权值*/
int getBothWeight(ALGraph &G,char X,char Y){
	int Y_sub = LocateVex(G,Y); 
	int X_sub = LocateVex(G,X);
	
	if(Y_sub == X_sub)	//为同一点 
		return 0;		
		
	ArcNode *p = G.vertices[X_sub].firstArc; 
	while(p){
		if(p->adjVex == Y_sub)		//找到 -> 返回权值 
			return p->info;
		p = p->nextArc;
	} 
	return  MaxWeight;				//未找到 -> 返回最大值 
}

/* 获取Dist数组内(未加入 S 集合,即S[i] == false)最小权值的下标 */
int getMinDist(int len,bool S[],int Dist[]){
	int min = MaxWeight;
	int min_sub = -1;
	for(int i=0;i<len;i++){
		if(!S[i] && Dist[i] < min){
			min = Dist[i];
			min_sub = i;
		}
	}
	return min_sub;
}

/*Dijkstra:迪杰斯特拉!*/
void shortTestPath_Dijkstra(ALGraph &G,char V){
	
	int n = G.vexnum;
	
	bool S[n] = {false};			//结点在S集合,则已生成最短路径
	//该结点的上一个结点下标,初始值 -1 为不连通,没有上一个连接点 
	int Path[n];					
	int Dist[n] = {MaxWeight};		//从V到各顶点的权值,MaxWeight代表没联通 
	
	//将原点加入到S集合中
	int v0 = LocateVex(G,V);			//V结点的下标 
	
	//n个顶点依次初始化
	for(int i=0;i<n;i++){
		char Y = G.vertices[i].data;			//要检查的顶点 Y
		Dist[i] =  getBothWeight(G,V,Y);		//获取 V -> Y 的长度
		//若不是最大值,代表 V 与 Y 有直接连通的路线,更新Path数组 
		if(Dist[i] < MaxWeight)					
			Path[i] =  v0;						//该节点的前驱为v0 
		else
			Path[i] = -1;						//与V结点不连通 
	} 
	
	
	S[v0] = true;						
	Dist[v0] = 0;						//原点到原点的距离为0 
	
	/*--初始化结束,开始主循环,每次求得v0到某个顶点k的最短路径,将K加到S集合--*/
	for(int i=1;i<n;i++){
		int k0 = getMinDist(n,S,Dist);	//获取Dist数组中没加入S集合的顶点 最小的权值 
		if(k0 == -1) 	//已找完 -- 剩下的为与 V 不连通的结点 
			break;
		char K = G.vertices[k0].data;			//最小权值连接的顶点名称  K
		S[k0] = true;							//将该顶点加入到S集合中
		 	
		//更新从v0出发到集合V-S上所有顶点的最短路径长度 
		for(int j=0;j<n;j++){					
			if(!S[j]){
				char Y = G.vertices[j].data;		//要检查的顶点 
				int w = getBothWeight(G,K,Y);		//获取 K -> Y 的长度
				//若从中转顶点K到该顶点Y的路径要小 -> 修改 
				if(Dist[k0] + w < Dist[j]){			
					Path[j] = k0;					//该顶点的前驱更改为 k0 
					Dist[j] = Dist[k0] + w;			//最短路径更新! 
				}
			}
		} 
	} 
	
	//输出 
	CoutResult(G,n,S,Path,Dist); 
} 

//输出结果
void CoutResult(ALGraph G,int n,bool S[],int Path[],int Dist[]){	
	cout << "集合:\t\t"; 
	for(int i=0;i<n;i++)
		cout << S[i] << "\t";
	cout << endl;
	
	cout << "前驱:\t\t"; 
	for(int i=0;i<n;i++)
		cout << G.vertices[Path[i]].data << "\t";
	cout << endl;
	
	cout << "到V的最短权值:\t"; 
	for(int i=0;i<n;i++)
		cout << Dist[i] << "\t";
	cout << endl;
	
} 
/*
Data(测试数据):
6 8
A B C D E F
A C 10
A E 30
A F 100
E D 20
E F 60
D F 10
C D 50
B C 5
*/

int main(){
	ALGraph G;
	if(CreateUDG(G)){
		cout<< "下标\t元素:\n";
		for(int i=0;i<G.vexnum;i++){
			cout<< i << "\t" << G.vertices[i].data << ":\t";
			ArcNode *p = G.vertices[i].firstArc;
			while(p){
				cout << "->" << p->adjVex <<  "\t";
				p = p->nextArc;
			}
			cout << endl;
		}
	}
	shortTestPath_Dijkstra(G,'A');
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值