迪杰斯特拉算法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;处顺序扫描顶点,找出最小值的点,那么整个算法过程中查找最小值将花费

迪杰斯特拉(Dijkstra)算法是一种寻找图中两间最短路径的经典算法,适用于无向图有向图,特别是当边权表示距离、费用或其他成本时。算法的基本思想是从起开始逐步探索邻接节,并始终选择当前已访问节到未访问节中代价最小的一条边作为下一步的前进方向。 在MATLAB中实现迪杰斯特拉算法通常涉及以下几个步骤: 1. **初始化**:创建一个二维数组或矩阵来存储各顶之间的距离,将所有初始值设置为无穷大,除了起到自身的距离设置为0;创建一个布尔型数组记录哪些节已经被处理过。 2. **选取最小距离节**:从未被处理过的节中选出距离起最近的一个节作为当前节。 3. **更新距离**:对于当前节的所有相邻节,如果从起通过当前节到相邻节的距离比之前记录的距离更小,则更新这个距离。 4. **标记已处理节**:将当前节标记为已经处理过。 5. **重复步骤2至4**,直到所有节都被处理或找到目标节。 MATLAB代码示例: ```matlab function [shortestPaths, processedNodes] = dijkstra(graphMatrix, startNode) % graphMatrix 是一个邻接矩阵,其中非零元素表示两个节间的距离。 % startNode 是起始节的位置。 % shortestPaths processedNodes 分别返回最短路径矩阵处理节状态。 n = size(graphMatrix, 1); visited = false(n, 1); % 初始化未访问节标志位 distances = inf(1, n); % 初始距离设为无穷大 distances(startNode) = 0; % 起始节距离设为0 for i = 1:n-1 current = find(~visited & (distances == min(distances(~visited))), 1); visited(current) = true; for j = 1:n if ~visited(j) && graphMatrix(current, j) ~= 0 newDist = distances(current) + graphMatrix(current, j); if newDist < distances(j) distances(j) = newDist; end end end end shortestPaths = distances; processedNodes = visited; ``` **相关问题**: 1. **如何优化迪杰斯特拉算法**?在大数据集上运行时,可以考虑使用优先队列来加速查找下一个最短路径候选节的过程。 2. **迪杰斯特拉算法与贝尔曼-福特算法的区别是什么**?贝尔曼-福特算法可以在存在负权重边的情况下求解最短路径,而迪杰斯特拉算法不支持负权重边。 3. **如何将迪杰斯特拉算法应用到实际问题中**?比如网络路由优化、地图导航系统中的路径规划等场景,都可以利用此算法来找到从源到所有其他的最短路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值