Dijkstra算法学习梳理

最近学习《数据结构与算法分析》一书,在“图论算法”一章再次接触到了Dijkstra算法,之前没有深入理解,这里对其原理进行梳理。

Dijkstra算法求解的是“单源最短路径问题”,是“贪婪算法”的一个很好的应用,按照我的理解就是“无权最短路径的类拓扑排序算法”+“调整策略”。而此处的调整策略就是“贪婪算法”的核心

下面简要介绍涉及的相关概念:

1.贪婪算法:简单地说就是程序运行的每一个当前时间点,都会选择对当前最有利的情况,如果之前的决策导致的结果没有现在的好,那就重新调整为当前的决策。(前提是当前时刻做出的决策与未来时刻无关,也就是满足“马尔可夫”过程)对应于Dijkstra算法,后续会提及具体体现的地方。

例子:购物找零钱时,商家为了省事,总会用尽量少的硬币给你,比如商家要找你五毛钱,那么总会用一个5毛硬币而不用五个1毛硬币,这里商家没有考虑后续顾客找零钱的情况。

2.拓扑排序:有向图中如果节点v指向w,那么按照拓扑排序后,w总出现在v后面。
一般解法是使用队列或栈的数据结构,按照一定的条件节点被划分为几个组,按顺序同一组的节点进入一个队列,此时其余组节点不进入此队列,队列中的节点处理完后出队,并在后续操作中不再涉及,只有当队列中所有节点处理完了,下一组节点才能进入该队列。

3.无权最短路径算法:一般采用“广度优先搜索”算法,结合下表分析

vknowndvpv
v1F0
v2F0
v3F00
v4F0
v5F0

在这里插入图片描述

这里v表示图中的节点,known表示该节点是否处理完(是否出列队,F表示未处理,T表示处理过了,当该节点被置为known后就要处理他的邻接点),*dv*表示该节点到出发点的距离,*pv*记录路径。

广度优先:首先选择出发点v3,计算离出发点距离=0,保留路径。处理完后将其known置为T(该节点在后续的程序中不再涉及);之后搜索该点的邻接点,记录它们到该点的距离并在表格中更新;随后对于邻接点按照其到上一个节点的距离从近到远处理,处理过程与上述过程一致,直到所有节点均被处理完,也就是表格中“known”列均为T。最终可以从表格""*pv*列得到最短路径。

4.Dijkstra算法:就是无权图最短路径算法中每条边的长度不再为1,代表的是两点间的距离。同样可以使用上述广度优先算法。
一般处理过程:
1)选取出发点计算其路径长(出发点为0),然后对其置known
2)调整该节点的邻接点(也就是计算邻接点的长度);
3)处理邻接点中长度最小的节点,将其置known,并计算其邻接点长度;
4)按长度从小到大依次处理剩余邻接点,依次标记为known,并计算它们各自的邻接点长度,如果计算结果小于之前的长度,则更新为当前时刻更小的长度(也就是“贪婪”的体现,说明当前路径可以有更好的结果),如果其邻接点在前述已被置为known,则跳过该节点。
5)重复执行过程3)和4),直到表格中最后一个长度最大的节点被置为known

结合下表与图进行说明:
算法的初始配置

vknowndvpv
v1F00
v2F0
v3F0
v4F0
v5F0
v6F0
v7F0

在这里插入图片描述
v1作为出发点:
v1被置为known

vknowndvpv
v1T00
v2F2v1
v3F0
v4F1v1
v5F0
v6F0
v7F0

v4被置为known

vknowndvpv
v1T00
v2F2v1
v3F3v4
v4T1v1
v5F3v4
v6F9v4
v7F5v4

v2被置为known

vknowndvpv
v1T00
v2T2v1
v3F3v4
v4T1v1
v5F3v4
v6F9v4
v7F5v4

v5被置为known

vknowndvpv
v1T00
v2T2v1
v3T3v4
v4T1v1
v5T3v4
v6F8v3
v7F5v4

v7被置为known

vknowndvpv
v1T00
v2T2v1
v3T3v4
v4T1v1
v5T3v4
v6F6v7
v7T5v4

v6被置为known后算法终止

vknowndvpv
v1T00
v2T2v1
v3T3v4
v4T1v1
v5T3v4
v6T6v7
v7T5v4

算法的伪代码如下

void dijkstra(Vertex s)
{
	for each Vertex v  // 初始化各节点
	{
		v.dist = INFINITY;
		v.known = false;
	}

	s.dist = 0;  // 初始节点长度为0

	while(there is an unknown distance vertex)  // 存在未处理的节点
	{
		Vertex v = smallest unknown distance vertex;  // 每次队列里仅含有同一组节点,选择最短的节点

		v.known = true;  // 节点置known

		for each Vertex w adjacent to v  // 节点的每一个邻接点
			if(!w.known)  // 如果邻接点之前未被处理过则执行以下过程
			{
				DistType cvw = cost of edge from v to w;  // 计算邻接点的长度

				if(v.dist + cvw < w.dist)  // 如果当前时刻的节点距离小于之前计算的结果,则进行更新(贪婪算法)
				{
					// Update w
					decrease(w.dist to v.dist + cvw);  // 更新节点的长度为更小的值
					w.path =v;  // 更新节点的路径
				}
			}
	}
}

参考书籍《数据结构与算法分析-Java语言描述》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值