欢迎探讨,如有错误敬请指正

如需转载,请注明出处 http://www.cnblogs.com/nullzx/


1. 算法的原理

以源点开始,以源点相连的顶点作为向外延伸的顶点,在所有这些向外延伸的顶点中选择距源点最近的顶点继续向四周延伸(某个顶点被选作继续延伸的顶点,则源点到它的最短距离就已经确定,我们也不再将其视为向外延伸的顶点了),如果在继续延伸的过程中遇到了之前已延伸到的顶点,且当前这次延伸过程使其离源点更近,我们就修正这个距离,直到所有的顶点都被视为继续延伸的顶点,此时我们就得到了源点到其它各个顶点的距离。

2. 一个具体的例子

在下面的例子中,模拟了dijkstra算法求解顶点3到其它各个顶点的最短距离。

黑色的顶点表示没有被延伸到的顶点,此时源点到它的距离为无穷。红色顶点表示已被延伸到的顶点,红色顶点旁的数字表示源点到它的距离。绿色顶点表示源点到该顶点的最短距离已确定。如果源点到某个顶点的距离被修正,我们将用黄色的方框将其标注。

distTo数组表示源点(下图中源点为顶点3)到各个顶点的距离,其中绿色的表示最短距离,红色表示这个距离是否是最短距离还未确定。

edgeTo数组表示源点3(下图中源点为顶点3)到各个顶点的路径,其中绿色的表示最短距离路径确定,红色表示这个距离是否是最短距离还未确定。edgeTo[i]表示经过顶点i的上一个顶点。

初始时,将源点看做向外延伸的顶点,它到自身的距离为0.0。每次向外延伸的过程中我们都会从红色的顶点中选择距离最近的顶点继续向外延伸,然后把该顶点标注成绿色。

下面是源点到各个节点的最短路径

最后我们从distTo和edgeTo数组就可以找到最短的距离和路径。

假设我们想得到源点,即顶点3,到顶点1的距离和路径。

distTo[1]的值为5.0,说明最短距离为5.0。

edgeTo[1]说明到顶点1的上一个顶点为顶点10,edgeTo[10]说明到顶点10的上一个顶点为4,edgeTo[4]说明到顶点4的上一个顶点为顶点3。也就是路径为3->4->10->1

3. 算法的证明

要证明算法的正确性,我们实际上需要证明:当从延伸顶点中选择离源点最近的顶点继续向外延伸时,源点到它的最短距离就已经确定了。

假设当前延伸顶点中最短的距离为t,同时存在一条路径从已访问到的顶点k经过某些未知顶点x到达t的距离更小。

已知distTo[s->t] <= distTo[s->k],

如果distTo[k->x]以及distTo[x->]都大于零, 那么

distTo[s->t] < distTo[s-k] + distTo[k->x] + distTo[x->]

上述不等式显然不会成立,所以算法的正确性得以证明。同时我们得出了Dijistra算法的适用情况:边的权值都为非负值

显然,如果是求给定两点st的最短距离,我们只需要在延伸的过程中将t作为继续向四周延伸的顶点时停止算法即可

4. 算法的实现

测试数据

8

15

4 5    0.35

5 4    0.35

4 7    0.37

5 7    0.28

7 5    0.28

5 1    0.32

0 4    0.38

0 2    0.26

7 3    0.39

1 3    0.29

2 7    0.34

6 2    0.40

3 6    0.52

6 0    0.58

6 4    0.93

输出结果

0 : [4 , 0.38] [2 , 0.26]

1 : [3 , 0.29]

2 : [7 , 0.34]

3 : [6 , 0.52]

4 : [5 , 0.35] [7 , 0.37]

5 : [4 , 0.35] [7 , 0.28] [1 , 0.32]

6 : [2 , 0.40] [0 , 0.58] [4 , 0.93]

7 : [5 , 0.28] [3 , 0.39]

1.51

0 2 0.26

2 7 0.34

7 3 0.39

3 6 0.52

源代码

package datastruct;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;

import datastruct.Graph.Edge;

public class Dijkstra {
	private double[] distTo;
	private Edge[] edgeTo;
	private PriorityQueue<DistTo> pq;
	private Graph g;
	private int s;

	//源点到顶点V的距离,
	public static class DistTo implements Comparable<DistTo>{
		public int idx;    //顶点的编号
		public double dist;//源点到顶点idx的短距离

		public DistTo(int v, double totalDist){
			this.idx = v;
			this.dist = totalDist;
		}

		@Override
		public int compareTo(DistTo that) {
			if(this.dist > that.dist){
				return 1;
			}else
			if(this.dist < that.dist){
				return -1;
			}else{
				return 0;
			}
		}
	}

	public Dijkstra(Graph g, int s){
		this.g = g;
		this.s = s;
		shortPath();
	}

	private void shortPath(){
		edgeTo = new Edge[g.V()];

		distTo = new double[g.V()];
		Arrays.fill(distTo, Double.POSITIVE_INFINITY);
		distTo[s] = 0.0;

		//如果到源点到顶点v的距离被多次修正,那么优先队列中就可能存在到顶点v的多个距离
		//所以以边的个数作为优先队列的最大长度
		pq = new PriorityQueue<DistTo>(g.E());

		pq.offer(new DistTo(s, 0.0));
		while(!pq.isEmpty()){
			DistTo v = pq.poll();//每次从优先队列中找到最近的延伸顶点
			for(Edge e : g.adjEdge(v.idx)){//从与idx顶点的出边继续向下延伸
				int to = e.to();
				if(v.dist + e.weight() < distTo[to]){
					edgeTo[to] = e;//修正路径
					distTo[to] = v.dist + e.weight();//修正距离
					pq.offer(new DistTo(to, distTo[to]));//修正后入列
				}
			}
		}
	}

	public double shortDistTo(int v){
		return distTo[v];
	}

	public List<Edge> shortPathTo(int v){
		LinkedList<Edge> stack = new LinkedList<Edge>();
		int to = v;
		if(distTo[to] == Double.POSITIVE_INFINITY){
			return stack;
		}

		while(edgeTo[to] != null){
			stack.push(edgeTo[to]);
			to = edgeTo[to].from();
		}
		return stack;
	}

	public static void main(String[] args) throws FileNotFoundException{
		File path = new File(System.getProperty("user.dir")).getParentFile();
		File f = new File(path, "algs4-data/tinyEWD.txt");
		FileReader fr = new FileReader(f);
		Graph g = new Graph(fr, true, true);
		System.out.println(g);

		Dijkstra dijkstra = new Dijkstra(g, 0);
		System.out.printf("%.2f\n", dijkstra.shortDistTo(6));
		List<Edge> shortPath = dijkstra.shortPathTo(6);
		for(Edge e : shortPath){
			System.out.println(e);
		}
	}
}

有关Graph类的实现可参照我技术博客的另一篇文章:

Kosaraju算法解析: 求解图的强连通分量

4. 参考内容

[1]. 算法(第4版)Robert Sedgewick 人民邮电出版社

[2]  Dijkstra算法(单源最短路径)

单源最短路径问题之dijkstra算法的更多相关文章

  1. 单源最短路径问题2 (Dijkstra算法)

    用邻接矩阵 /* 单源最短路径问题2 (Dijkstra算法) 样例: 5 7 0 1 3 0 3 7 1 2 4 1 3 2 2 3 5 2 4 6 3 4 4 输出: [0, 3, 7, 5, 9 ...

  2. 图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法

    Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但要求所有边的权值非负. Dijkstra算法是贪婪算法的一个很好的例子.设置一顶点集合S,从源点s到集合中的顶点的最终最短路径 ...

  3. 单源最短路径—Bellman-Ford和Dijkstra算法

    Bellman-Ford算法:通过对边进行松弛操作来渐近地降低从源结点s到每个结点v的最短路径的估计值v.d,直到该估计值与实际的最短路径权重相同时为止.该算法主要是基于下面的定理: 设G=(V,E) ...

  4. 单源最短路径问题1 (Bellman-Ford算法)

    /*单源最短路径问题1 (Bellman-Ford算法)样例: 5 7 0 1 3 0 3 7 1 2 4 1 3 2 2 3 5 2 4 6 3 4 4 输出: [0, 3, 7, 5, 9] */ ...

  5. 图->最短路径->单源最短路径(迪杰斯特拉算法Dijkstra)

    文字描述 引言:如下图一个交通系统,从A城到B城,有些旅客可能关心途中中转次数最少的路线,有些旅客更关心的是节省交通费用,而对于司机,里程和速度则是更感兴趣的信息.上面这些问题,都可以转化为求图中,两 ...

  6. 单源最短路径-迪杰斯特拉算法(Dijkstra's algorithm)

    Dijkstra's algorithm 迪杰斯特拉算法是目前已知的解决单源最短路径问题的最快算法. 单源(single source)最短路径,就是从一个源点出发,考察它到任意顶点所经过的边的权重之 ...

  7. 单源最短路径 Bellman_ford 和 dijkstra

    首先两个算法都是常用于 求单源最短路径 关键部分就在于松弛操作 实际上就是dp的感觉 if (dist[e.to] > dist[v] + e.cost) { dist[e.to] = dist ...

  8. PAT甲级——1111 Online Map (单源最短路经的Dijkstra算法、priority_queue的使用)

    本文章同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90041078   1111 Online Map (30 分) ...

  9. 单源最短路:Dijkstra算法 及 关于负权的讨论

    描述: 对于图(有向无向都适用),求某一点到其他任一点的最短路径(不能有负权边). 操作: 1. 初始化: 一个节点大小的数组dist[n] 源点的距离初始化为0,与源点直接相连的初始化为其权重,其他 ...

随机推荐

  1. JTree实例

    JTree实例 private void createTreeByXdDdt() { DefaultComboBoxModel boxModel = (DefaultComboBoxModel) cm ...

  2. 在ASP.NET MVC3项目中,自定义404错误页面

    在Web开发中,用户体验是至关重要的,一个友好的网站自然少不了自定义404错误页面. 让笔者为大家介绍404错误页面在ASP.NET MVC3项目中的配置: 第一步,在项目的Web.config文件中 ...

  3. Oracle Job 语法和时间间隔的设定(转)

    http://blog.itpub.net/27157/viewspace-425567/ 初始化相关参数job_queue_processesalter system set job_queue_p ...

  4. 为 Jenkins 配置 .Net 持续集成环境

    去年年底,得益于公司引入 Jenkins,让我们在持续集成方面迈出了第一步,本文不赘述如何安装 Jenkins,主要关注点在于配置 .Net 环境.另外本文是在 Windows 环境下安装的 Jenk ...

  5. asp.net权限认证:OWIN实现OAuth 2.0 之密码模式(Resource Owner Password Credential)

    asp.net权限认证系列 asp.net权限认证:Forms认证 asp.net权限认证:HTTP基本认证(http basic) asp.net权限认证:Windows认证 asp.net权限认证 ...

  6. iOS RunTime你知道了总得用一下

    说点题外话: 我刚来现在这家公司的时候,老板让我下载一个脉脉,上去找找自己的同行,多认识些同行.其实初衷的好的,但最近这两天我把它卸载了,不为别的,负能量太多!iOS这行自从2016就没景气过,在这行 ...

  7. AJSX 传输数组

    如果要利用ajax传输数组,或者传输多个(不知道有多少个)class的某一属性的值,例如: 要将这三个数据传入php编辑界面,图片显示有三个数据,但实际上,数据的多少是由数据库所导出的数据 决定的.如 ...

  8. git用法-打补丁

    1. git cherry-pick 作用:从一个branch上选择一个commit,添加该commit到另一个branch上. 1. 切换到你想添加commit的分支上. git checkout ...

  9. JAVA试练塔之试炼技能图

    1.计算机基础: 1.1数据机构基础: 主要学习: 1.向量,链表,栈,队列和堆,词典.熟悉 2.树,二叉搜索树.熟悉 3.图,有向图,无向图,基本概念 4.二叉搜索A,B,C类熟练,9大排序熟悉. ...

  10. win8配置JDK

    有很多新手朋友对win7 和win8里的环境变量不是很熟悉,下面我整理了一下: 首先要说一下,win7里和win8配置方法是相同的,配置之前先去百度一下 JDK 然后找到自己电脑系统对应的jdk版本下 ...