数据结构之图的应用:最短路径(Dijkstra、Floyd)

思维导图:

在这里插入图片描述

最短路径的定义:

在这里插入图片描述

BFS算法:(无权单源最短路径)

在这里插入图片描述在这里插入图片描述

void BFS_Distance(Graph G,int v){
	for(int i=0;i<G.vexnum;++i)
		d[i] = MAX;
	visited[v] = true;
	d[v] = 0;
	EnQueue(Q,v);
	while(!isEmpty(Q)){		//不空还有未遍历到的节点 
		DeQueue(Q,v);		//出队v 
		for(w = FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))		//找到所有符合条件的邻接节点 
			if(!visited[w]){		//w是否被访问  
				visited[w] = true;	//修改该顶点对应数组的值为true
				d[w] = d[v] + 1;
				EnQueue(Q,w);		//入队 
			}
	}
}

Dijkstra算法:(无权单源、带权单源)

后续补充:至原理之前
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

Dijkstra算法原理:

注: 此算法只解决单源问题,即从一个确定顶点到其他所有顶点的路径问题
在这里插入图片描述
ps:

1、先初始化一个空结果集
2、让某一节点进入结果集
3、从非结果集中的顶点中选出一条最小权重的边,并将该边的另一个顶点加入结果集
4、从结果集的顶点出发到新加入的顶点的路径不止一条,要从多条路径中选出最短的一条,并修改对应数组值
5、重复3、4操作直到所有的顶点都加入到结果集中

要是实在看不懂,下面有具体实例讲解

算法实现中的辅助数组:

在这里插入图片描述
算法实现中用到的辅助数组:

1、s[]数组:标记已经加入了结果集的顶点
2、dist[]数组:从一个v0(某一个确定的节点)出发到各个节点的最短路径,若有多条路径选择最短的一条记录
3、path[]数组:记录到达该节点的前驱节点的数组下标,A->B->C,到达C的前驱节点为B

例:

这是重点,帮助理解;这是重点,帮助理解
在这里插入图片描述在这里插入图片描述
后续的思路与上述相同,就不再赘述。

如何通过path[]数组找到0到其他顶点的路径?

在这里插入图片描述
ps:
因为path[4] = 2,即4的前驱是2
又path[2] = 0,即2的前驱又是0
又path[0] = -1,即0就是序列头节点
所有得到了序列0—>2—>4
其他原理类似,不在赘述

Dijkstra算法的代码实现:

void Dijkstra(Graph G,int v){		//图和源点 
	//初始化三个数组 
	int s[G.vexnum];
	int path[G.vexnum];
	int dist[G.vexnum];
	for(int i=0;i<G.vexnum;i++){	
		dist[i] = G.edge[v][i];
		s[i] = 0;
		if(G.edge[v][i] < MAX)
			path[i] = v;
		else
			path[i] = -1;
	} 
	s[v] = 1;
	path[v] = -1;
	//寻找dist[]数组最小值 
	for(i=0;i<G.vexnum;i++){
		int min = MAX;
		int u;
		for(int j=0;j<G.vexnum;j++)
			if(s[j]==0 && dist[j]<min){
				min = dist[j];
				u = j;
			}
		s[u] = 1;			//将u加入结果集 
		//加入了新的节点,更新数组 
		for(int j=0;j<G.vexnum;j++)
			if(s[j]==0 && dist[u]+G.Edge[u][j] < dist[j]){
				dist[j] = dist[u]+G.Edge[u][j];
				path[j] = u;
			}
	}
} 

Dijkstra算法适用范围及性能:

时间复杂度:O(|V|2)
存在负权值的图无法用Dijkstra算法
在这里插入图片描述

在这里插入图片描述

Floyd算法:

后期补充:至算法原理之前
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Floyd算法原理:(动态规划)

在这里插入图片描述
A(0)矩阵表示加入0节点后的矩阵
A(1)矩阵表示加入节点1后的矩阵
ps:
在原来的结果集中加入一个节点k
节点i到节点k原有路径 与 经过k的路径比较
选最短的一条

例:

在这里插入图片描述
在这里插入图片描述

Floyd算法的代码实现:

void Floyd(Graph G){
	int A[G.vexnum][G.vexnum];
	//初始化
	for(int i=0;i<G.vexnum;i++)
		for(intj=0;j<G.vexnum;j++)
			A[i][j] = G.Edge[i][j];
	//对每一个值进行修改
	for(int k=0;k<G.vexnum;k++)			//考虑以Vk作为中转点
		//修改某个值
		for(int i=0;i<G.vexnum;i++)		//遍历矩阵i为行号,j为列号
			for(intj=0;j<G.vexnum;j++)
				if(A[i][j] > A[i][k] + a[k][j])		//判断路径是否最优
					A[i][j] = A[i][k] + a[k][j];	//更新最短路径长度
				  //path[i][j] = k;
}

性能分析:

时间复杂度:O(|V|^3)
空间复杂度:O(|V|^2)

例:

在这里插入图片描述

缺点:

在这里插入图片描述

三种算法的对比:

在这里插入图片描述

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值