单源最短路径问题之dijkstra算法
欢迎探讨,如有错误敬请指正
如需转载,请注明出处 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算法的适用情况:边的权值都为非负值。
显然,如果是求给定两点s到t的最短距离,我们只需要在延伸的过程中将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类的实现可参照我技术博客的另一篇文章:
4. 参考内容
[1]. 算法(第4版)Robert Sedgewick 人民邮电出版社
单源最短路径问题之dijkstra算法的更多相关文章
- 单源最短路径问题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 ...
- 图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法
Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但要求所有边的权值非负. Dijkstra算法是贪婪算法的一个很好的例子.设置一顶点集合S,从源点s到集合中的顶点的最终最短路径 ...
- 单源最短路径—Bellman-Ford和Dijkstra算法
Bellman-Ford算法:通过对边进行松弛操作来渐近地降低从源结点s到每个结点v的最短路径的估计值v.d,直到该估计值与实际的最短路径权重相同时为止.该算法主要是基于下面的定理: 设G=(V,E) ...
- 单源最短路径问题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] */ ...
- 图->最短路径->单源最短路径(迪杰斯特拉算法Dijkstra)
文字描述 引言:如下图一个交通系统,从A城到B城,有些旅客可能关心途中中转次数最少的路线,有些旅客更关心的是节省交通费用,而对于司机,里程和速度则是更感兴趣的信息.上面这些问题,都可以转化为求图中,两 ...
- 单源最短路径-迪杰斯特拉算法(Dijkstra's algorithm)
Dijkstra's algorithm 迪杰斯特拉算法是目前已知的解决单源最短路径问题的最快算法. 单源(single source)最短路径,就是从一个源点出发,考察它到任意顶点所经过的边的权重之 ...
- 单源最短路径 Bellman_ford 和 dijkstra
首先两个算法都是常用于 求单源最短路径 关键部分就在于松弛操作 实际上就是dp的感觉 if (dist[e.to] > dist[v] + e.cost) { dist[e.to] = dist ...
- PAT甲级——1111 Online Map (单源最短路经的Dijkstra算法、priority_queue的使用)
本文章同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90041078 1111 Online Map (30 分) ...
- 单源最短路:Dijkstra算法 及 关于负权的讨论
描述: 对于图(有向无向都适用),求某一点到其他任一点的最短路径(不能有负权边). 操作: 1. 初始化: 一个节点大小的数组dist[n] 源点的距离初始化为0,与源点直接相连的初始化为其权重,其他 ...
随机推荐
- Android4.0新增的网格布局
网格布局由GridLayout代表,它是Android 4.0新增的布局管理器,因此需要在Android 4.0 之后的版本中才能使用该布局管理器.如果希望在更早的Android平台上使用该布局管理器 ...
- PHP中目录解析函数
dirname(string path):给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名. 斜线(/)和反斜线(\)都可以用作目录分隔符.在其它环境下是斜线(/). dir ...
- 算法一之N皇后问题
(写这篇文章主要是明天就要考试了,算法考试,今天不想再复习了,xiang着今天也开通了博客,于是在这个平台上进行复习,应该会更高效.最后祝愿我明天考个好成绩.嘻嘻...) n皇后问题,主要是应用到回溯 ...
- Flex中操作XML的E4X方法
用于处理 XML 的 E4X 方法 Flash Player 9 和更高版本,Adobe AIR 1.0 和更高版本 ECMAScript for XML 规范定义了一组用于使用 XML 数据的类 ...
- SSM(Maven集成)
ssm全称:Spring+SpringMVC+Mybatis ssm简介: 1.Spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod J ...
- 个人对现在大众对perl的偏见的一些见解
最近我都在一些论坛和交流社区学习,发现很多人对perl有很大的偏见. 以我学习那么久的Perl来说吧,也算是有一些小经验了,所以我总结了大家对perl的偏见的原因,无非就是是下面两个的两个原因: 1. ...
- TypeScript教程2
在TS中,我们允许开发人员使用面向对象技术. 1.类让我们看看一个简单的基于类的例子: class Greeter { greeting: string; constructor(message: s ...
- java系列笔记---正则表达式(1)常用符号
正则表达式---常用符号 首先声明,我这里列表的是经常使用的一些符号,如果你想得到全部,那建议你通过API中,搜索Pattern类,会得到所有符号. 字符类 [abc] a.b 或 c(简单类) [^ ...
- Ionic start 创建项目报错 Error with start undefined
转自:http://blog.csdn.net/wenzigui_qy/article/details/52874542 在Installing npm packages的时候报错,如下: Insta ...
- XmlHepler(拿去就能用)
[系列目录](./XmlCatalog.html) 前言 本篇是这个系列的最后一篇.也是本人第一次写系列文章,虽然系列中大部分内容都是参考网络,但是自己都有敲代码验证.自己再编写过程中也学习到了很多知 ...
