图的最短路径---迪杰斯特拉(Dijkstra)算法浅析
什么是最短路径
在网图和非网图中,最短路径的含义是不一样的。对于非网图没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径。
对于网图,最短路径就是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点为源点,最后一个顶点为终点。
解决最短问题的算法
Dijkstra算法
Floyd算法
SPFA算法
Dijkstra算法描述
算法的特点:Dijkstra算法使用广度优先搜索解决赋权有向图或无向图的单源最短路径问题,最终得到一个最短路径树
算法的思路:Dijkstra算法采用贪心的策略,声明一个数组ShortPathTable保存源点到各顶点的带权长度,声明一个数组Patharc来保存最短路径前驱顶点。
初始化时,源点v0v_0v0的路径权重被赋予0(ShortPathTable[v0v_0v0] = 0),表示v0v_0v0到v0v_0v0的路径为0。对于顶点v0v_0v0能够直接到达的边(v0v_0v0,vwv_wvw),将ShortPathTable[vwv_wvw]设为该边的权重,对于v0v_0v0不能直接到达的所有顶点,将路径权重设为无限大。
初始时,Patharc的值全为0。还需要一个中间数组fin来表示是否已经求得源点v0v_0v0到vwv_wvw的最短路径,初始化时该数组值全部置为0,且将fin[v0v_0v0]=1,表示v0v_0v0到v0v_0v0不需要求路径。
算法执行时,从ShortPathTable数组中选择最小值,该值为源点v0v_0v0到该边对应顶点vkv_kvk的最小路径。修改fin[vkv_kvk]=1,表示目前已经找到最近的顶点。同时修正当前最短路径及距离。完成一次循环。
算法示例
我们求v0v_0v0到v8v_8v8的最短路径
ps:这个图应该竖着看…

第一步
初始化ShortPathTable为[0, 1, 5, ∞, ∞, ∞, ∞, ∞, ∞];fin数组为[1, 0, 0, 0, 0, 0, 0, 0],Patharc初始化为[0, 0, 0, 0, 0, 0, 0, 0]。
第二步
我们先找离源点最近的顶点,从ShortPathTable数组中可以得到离源点最近的顶点为v1v_1v1,且最近距离为1,所以此时v1v_1v1对应的fin[1]设为1,此时fin数组为[1, 1, 0, 0, 0, 0, 0, 0]。
第三步
在已经找到的v0v_0v0到v1v_1v1的最短路径基础上,对v1v_1v1与其他顶点的边进行计算,得到v0v_0v0与它们的当前最短距离。根据例子,min=1,所以本来ShortPathTable[2]=5,表示源点直接到达v2v_2v2的距离为5,但是现在通过v1v_1v1,源点到达v2v_2v2的距离为min+3=4 < 5。v3v_3v3,v4v_4v4也是一个道理。我们既然发现通过v1v_1v1到达其他顶点的距离如果小于源点直接到达该顶点的距离,那么我们就要修正ShortPathTable数组,此时ShortPathTable为[0, 1, 4, 8, 6, ∞, ∞, ∞, ∞],这个过程有个专业术语叫松弛,即 v0v_0v0顶点到v2v_2v2顶点(还有v3v_3v3,v4v_4v4)的路程即 ShortPathTable[2],通过 < v1v_1v1,v2v_2v2> 这条边松弛成功。这是 Dijkstra 算法的主要思想:通过“边”来松弛源点到其余各个顶点的路程。
而Patharc数组就是为了记录源点到某一顶点的最短路径它们的前驱为哪个顶点。以现在为例,Patharc[2]=Patharc[3]=Patharc[4]=1,表示源点v0v_0v0到v2v_2v2,v3v_3v3,v4v_4v4点的最短路径它们的前驱均为v1v_1v1。
第四步
使用同样的原理,重新开始循环。
算法实现
对于上述网图的邻接矩阵为:
//INFINITY表示无穷大,程序中可以以65535代替
{
	{0, 1, 5, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY },
	{1, 0, 3, 7, 5, INFINITY, INFINITY, INFINITY, INFINITY },
	{5, 3, 0, INFINITY, 1, 7, INFINITY, INFINITY, INFINITY },
	{INFINITY, 7, INFINITY, 0, 2, INFINITY, 3, INFINITY, INFINITY },
	{INFINITY, 5, 1, 2, 0, 3, 6, 9, INFINITY},
	{INFINITY, INFINITY, 7, INFINITY, 3, 0, INFINITY, 5, INFINITY},
	{INFINITY, INFINITY, INFINITY, 3, 6, INFINITY, 0, 2, 7},
	{INFINITY, INFINITY,INFINITY, INFINITY, 9, 5, 2, 0, 4},
	{INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, 7, 4,0}
}
具体程序如下:
package 最短路径;
/**
 * 迪杰斯特拉算法
 * @author shanlei
 *
 */
public class Dijkstra {
	private final int INFINITY = 65535;
	public int MAXVEX;
	public int[] Patharc; //P[v]的值为前驱顶点下标
	public int[] ShortPathTable; //D[v]表示v0到v的最短路径长度和
	/**
	 * 在这里直接使用矩阵了,忽略了网图转化为矩阵的过程
	 */
	public int[][] maze = {
            {0, 1, 5, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY },
            {1, 0, 3, 7, 5, INFINITY, INFINITY, INFINITY, INFINITY },
            {5, 3, 0, INFINITY, 1, 7, INFINITY, INFINITY, INFINITY },
            {INFINITY, 7, INFINITY, 0, 2, INFINITY, 3, INFINITY, INFINITY },
            {INFINITY, 5, 1, 2, 0, 3, 6, 9, INFINITY},
            {INFINITY, INFINITY, 7, INFINITY, 3, 0, INFINITY, 5, INFINITY},
            {INFINITY, INFINITY, INFINITY, 3, 6, INFINITY, 0, 2, 7},
            {INFINITY, INFINITY,INFINITY, INFINITY, 9, 5, 2, 0, 4},
            {INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, 7, 4,0}
        };
	//简单的初始化数据
	public Dijkstra() {
		this.MAXVEX = this.maze.length;
		this.Patharc = new int[MAXVEX];
		this.ShortPathTable = new int[MAXVEX];
	}
	//Dijkstra
	public void ShortestPath_Dijkstra(int v0) {
		int v, w, k = 0, min;
		int[] fin = new int[MAXVEX]; //表示已经求得顶点v0到vw的最短路径
		//初始化
		for (v = 0; v < MAXVEX; v++) {
			fin[v] = 0;
			Patharc[v] = 0;
			ShortPathTable[v] = this.maze[v0][v];
		}
		ShortPathTable[v0] = 0;
		fin[v0] = 1;
		/**
		 * 主循环
		 */
		for (v = 1; v < MAXVEX; v++) {
			min = INFINITY;
			for (w = 0; w < MAXVEX; w++) {
				if((fin[w] == 0) && (ShortPathTable[w] < min)) {
					k = w;
					min = ShortPathTable[w];
				}
			}
			fin[k] = 1;
			/**
			 * 修正当前最短路径及距离
			 */
			for (w = 0; w < MAXVEX; w++) {
				//如果经过v顶点的路径比现在这条路径的长度短的话
				if((fin[w] == 0) && ((min + maze[k][w]) < ShortPathTable[w])) {
					//说明找到了更短的路径,修改D[w]和P[w]
					ShortPathTable[w] = min+ maze[k][w];
					Patharc[w] = k;
				}
			}
			/**
			 * 算法执行过程
			 * 输出算法执行过程中的数据和最终最短路径
			 */
			System.out.println("min=" + min);
			System.out.println("---- final array --- ");
			for (int i = 0; i < fin.length; i++) {
				System.out.print(fin[i] + "  ");
			}
			System.out.println();
			System.out.println("---- D array --- ");
			for (int i = 0; i < ShortPathTable.length; i++) {
				System.out.print(ShortPathTable[i] + "  ");
			}
			System.out.println();
			System.out.println("---- P array --- ");
			for (int i = 0; i < Patharc.length; i++) {
				System.out.print(Patharc[i] + "  ");
			}
			System.out.println();
			System.out.println();
			System.out.println();
		}
		for (int i = 0; i < ShortPathTable.length; i++) {
			System.out.print("D[" + i + "]=" + ShortPathTable[i] + "  ");
		}
		System.out.println();
		int z = Patharc.length - 1;
		while(true) {
			if(z==0) {
				System.out.print(z);
				break;
			}
			System.out.print(z + "<-");
			z = Patharc[z];
		}
	}
	public static void main(String[] args) {
		Dijkstra d = new Dijkstra();
		d.ShortestPath_Dijkstra(0);
	}
}
迪杰斯特拉解决了从某个源点到其余各顶点的最短路径问题,从嵌套循环可以得出该算法的时间复杂度为O(n2n^2n2),其中每次找到离源点最近的顶点的时间复杂度是O(N),我们可以使用“堆”来进行优化,使得这一部分的时间复杂度降低到O(logN)。
另外对于边数M少于N2N^2N2的稀疏图来说(我们把M远小于N2N^2N2的图称为稀疏图,而M相对较大的图称为稠密图),我们可以用邻接表来代替邻接矩阵,使得整个时间复杂度优化到O(MlogN)。请注意!在最坏的情况下M就是N2N^2N2,这样的话MlogN要比N2N^2N2还要大。但是大多数情况下并不会有那么多边,因此MlogN要比N2N^2N2小很多。
参考:https://www.cnblogs.com/wangyuliang/p/9216511.html
图的最短路径---迪杰斯特拉(Dijkstra)算法浅析的更多相关文章
- 最短路径-迪杰斯特拉(dijkstra)算法及优化详解
		
简介: dijkstra算法解决图论中源点到任意一点的最短路径. 算法思想: 算法特点: dijkstra算法解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树.该算法常用于路由算 ...
 - 最短路径 - 迪杰斯特拉(Dijkstra)算法
		
对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点为源点,最后一个顶点为终点.最短路径的算法主要有迪杰斯特拉(Dijkstra)算法和弗洛伊德(Floyd ...
 - JS实现最短路径之迪杰斯特拉(Dijkstra)算法
		
最短路径: 对于网图来说,最短路径是指两个顶点之间经过的边上权值和最少的路径,我们称第一个顶点是源点,最后一个顶点是终点 迪杰斯特拉 ( Dijkstra) 算法是并不是一下子就求出 了 Vo 到V8 ...
 - [从今天开始修炼数据结构]图的最短路径 —— 迪杰斯特拉算法和弗洛伊德算法的详解与Java实现
		
在网图和非网图中,最短路径的含义不同.非网图中边上没有权值,所谓的最短路径,其实就是两顶点之间经过的边数最少的路径:而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,我们称路径上第 ...
 - 最短路径算法-迪杰斯特拉(Dijkstra)算法在c#中的实现和生产应用
		
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思想),直到扩展到终点为止 贪心算法(Greedy ...
 - 迪杰斯特拉Dijkstra算法介绍
		
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijk ...
 - 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(二)
		
一.基于邻接表的Dijkstra算法 如前一篇文章所述,在 Dijkstra 的算法中,维护了两组,一组包含已经包含在最短路径树中的顶点列表,另一组包含尚未包含的顶点.使用邻接表表示,可以使用 BFS ...
 - 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(一)
		
一.算法介绍 迪杰斯特拉算法(英语:Dijkstra's algorithm)由荷兰计算机科学家艾兹赫尔·迪杰斯特拉在1956年提出.迪杰斯特拉算法使用了广度优先搜索解决赋权有向图的单源最短路径问题. ...
 - C# 迪杰斯特拉(Dijkstra)算法
		
Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 其基本思想是,设置顶点集合S并不断地作 ...
 
随机推荐
- Mac  安装Django
			
首先 我电脑上的python 是 安装Django 是需要通过 pip 来安装的 最新办的python3.4 应该内置了pip 因此这里 需要下载安装pip pip是常用的Python包管理 ...
 - jsp页面拨打电话和QQ聊天
			
拨打电话: <a href="tel:手机号">拨打电话</a> 这种方式塞班.安卓与iphone都支持. 参考文章:https://blog.csdn.n ...
 - MongoHelper
			
/* @@decription mongodbHelper @@version 1.0 @@author think_fish&&dachie @@copyright think_fi ...
 - sql时间戳转日期格式
			
FROM_UNIXTIME(ctime, '%Y-%m-%d %H:%i:%s')
 - Java程序设计9——泛型
			
泛型是对集合的补充,JDK1.5增加泛型支持很大程度上都是为了让集合能记住其元素的数据类型.在没有泛型之前,一旦把一个对象丢进Java集合中,集合就会忘记对象的类型,把所有的对象都当成Object类型 ...
 - http://4526621.blog.51cto.com/4516621/1343369
			
http://4526621.blog.51cto.com/4516621/1343369
 - 矩阵乘法np.dot()及np.multiply()以及*
			
转载自 https://blog.csdn.net/u012609509/article/details/70230204 Python中的几种矩阵乘法 1. 同线性代数中矩阵乘法的定义: np.do ...
 - meterpreter命令
			
meterpreter详解与渗透实战 基本命令: background quit shell irb client.sys.config.sysinfo() 调用windows API:client. ...
 - 51nod1057—N的阶乘—(大数阶乘)
			
1057 N的阶乘 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 输入N求N的阶乘的准确值. Input 输入N(1 <= N <= ...
 - Java垃圾收集调优实战
			
1 资料 JDK5.0垃圾收集优化之--Don't Pause(花钱的年华) 编写对GC友好,又不泄漏的代码(花钱的年华) JVM调优总结 JDK 6所有选项及默认值 2 GC日志打印 GC调 ...