迪杰斯特拉算法Dijkstra

今天要写yen’s algorithm,其中要用到Dijkstra,所以好好学习了一下。

算法简介

Dijkstra是典型最短路径算法,用于计算赋权图中单源最短路径问题——一个节点到其他所有节点的最短路径及长度、各个最短路径所包含的节点——但是,请注意,Dijkstra虽是寻找最短路径的算法,但是找到的最短路径并不止一条,因为它会找从起点到每个节点间的最短路径的集合。还有,Dijkstra算法要求图中不存在负权边

自认:之所以要强调赋权图,是因为在无权图中,Dijkstra蜕变为图的广度优先遍历,原因详见算法思想处。

虽然一会要看到的代码中,结束条件是所有节点都遍历到了,但是目的是确定起点到所有节点的最短路径的最终距离。一定要跟最小生成树的算法区分开,不要混淆。

此外,值得一提的是,它是贪婪算法最好的例子

贪婪算法

贪婪算法一般分阶段求解一个问题,在每个阶段它都把出现的当做是最好的去处理——(自认)即在每一步都选择当前的最好选项。待细补。

算法思想

Dijkstra的基本思想,简单来说,是以起始点为中心向外层层扩展(广度优先遍历思想,也有点像树的层序遍历),直到扩展到终点为止。之所以说它像广度优先是因为,它每次都选择距离起点(注意,而非当前查找过程中所在的点)最近的点——依据离起点的远近,依次选择各点(近的优先)。并在选择这些点后,更新与它直接相邻的各个节点到起点的距离,直至所有点都遍历一遍为止。

具体来说,就是:
①在开始时,将所有节点的(到起点)距离设为无穷大;全部(包括起点)纳入不确定集合中。

②选择起点,将其(到起点)距离设为0。因为自己到自己的距离肯定为0。

③循环地从不确定集合中选择一个节点,加入确定集合。
当不确定集合为空时,此循环结束。
其中,每次选择的节点,都是选择离起点最近的点——即具有最小(到起点)距离,加入到确定节点集中(但此时数值不一定固定、准确,即不到算法终止,结果都不一定准确)。这里多提一句,第一次一定会选择起点加入确定集合,因为第二步将起点的距离设为0,而其余的点距离还是无穷大。

每次有节点加入到确定集合时,都会更新图中与新加入节点相连的所有点 (到起点) 的距离。其中(1)不论与新加入节点相连的点在确定集合还是不确定集合(2)更新距离时,只需考虑“与新加入节点相邻的这些节点”已有的(到起点)路径短,还是通过新加入节点到起点的距离短,即可。若通过新加入节点到起点更短,则换成新加入节点。用代码描述(2)中的判断就是if(v.dist + cvw < w.dist))

算法实现

此处仅给出伪代码和Java的代码实现。

伪代码

//Dijkstra中要用到的点的结构
class Vertex{
	/*自认这个变量没有用,但是有书上给出这一项,所以还是放在这里,供大家参考*/
	public List	adj;//Adjacent list
	/***********************************************************************/
	public boolean known; //表示该点是否已确定到起点的最短路径
	public int dist; //表示当前点到起点的距离。因为前面已经说到,Dijkstra是用来求一个点到图中所有点之间的最短路径,所以这里的起点是指那一个点。
	public Vertex path; //记录自己(所在的路径序列中)的上一节点,用来遍历、记录找到的最短路径使用。
}

void dijkstra(Vertex s){

	/*********************************初始化所有节点***************************************/
	for each Vertex v
	{
		v.dist = INFINITY;//将所有节点到起点 s 的距离设为无穷大
		v.known = false;//将所有节点标为未确定,即还未加入路径
	}
	/*****************************************************************************************/
	
	s.dist = 0; //将起点自己的dist设为0(因为dist这一属性专门记录各个节点到起点的距离,所以起点自己到自己的距离肯定是0)
	
	for( ; ; ){  //一直循环,直到触发break
		Vertex v = smallest distance and unknown vertex; //从未确定的点集中取出距离起点最近的点
		if(v==null) break; //若取到的点是空,即已无点可取
		v.known = true; //将该点加入确定点

		/*********************************更新距离***********************************/
		for each Vertex w adjacent to v  //只遍历、选出与新加入节点v相连的节点w
			if( !w.known ) //如果w还是未确定的点
				//因为距离还未确定,所以比较,若是更近则更新
				if(v.dist + cvw < w.dist){ //自认,cvw是指当前所选节点w与新加入节点v的距离
					//即若发现新加入节点v周围的节点w们,通过v到起点的距离 比它们现有到起点的距离少,则更新对应的dist和用于存储上一节点的项path
					w.dist = v.dist + cvw;
					w.path = v;
				}
		/*****************************************************************************/
	} 
	
}

Java版

在这里插入代码片

算法示例

动态图

算法分析

通过反证法的证明,我们可以知道,只要没有权值为负的边存在,Dijkstra总是能够顺利工作。

时间复杂度分析

书P248补
运行时间依赖对顶点的处理方法:若在
Vertex v = smallest distance and unknown vertex;处顺序扫描顶点,找出最小值的点,那么整个算法过程中查找最小值将花费

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值