Dijkstra算法详细(单源最短路径算法)

Dijkstra算法详细(单源最短路径算法)

闪念基因2019-12-01 10:04:30

介绍

对于 dijkstra 算法,很多人可能感觉熟悉而又陌生,可能大部分人比较了解 bfs和dfs ,而对dijkstra和floyd算法可能知道大概是图论中的某个算法,但是可能不清楚其中的作用和原理,又或许,你曾经感觉它很难,那么,这个时候正适合你重新认识它。

Dijkstra能是干啥的?

Dijkstra是用来求单源最短路径的

就拿上图来说,假如直到的路径和长度已知,那么可以使用 dijkstra 算法计算 南京到图中所有节点的最短距离。

单源什么意思?

  • 从一个顶点出发,Dijkstra算法只能求一个顶点到其他点的最短距离而不能任意两点。

和 bfs 求的最短路径有什么区别?

  • bfs 求的与其说是路径,不如说是 次数 。因为bfs他是按照队列一次一次进行加入相邻的点,而两点之间没有权值或者权值相等(代价相同)。处理的更多是偏向迷宫类的这种都是只能走邻居(不排除特例)。

Dijkstra在处理具体实例的应用还是很多的,因为具体的问题其实带权更多一些。

比如一个城市有多个乡镇,乡镇可能有道路,也可能没有,整个乡镇联通,如果想计算每个乡镇到a镇的最短路径,那么Dijkstra就派上了用场。

算法分析

对于一个算法,首先要理解它的 运行流程

对于一个Dijkstra算法而言,前提是它的前提条件和环境:

  • 一个连通图,若干节点,节点可能有数值,但是 路径 一定有 权值 。并且路径 不能为负 。否则Dijkstra就不适用。

Dijkstra的核心思想是贪心算法的思想。不懂贪心?

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

对于贪心算法,在很多情况都能用到。下面举几个不恰当的例子!

打个比方,吃自助餐,目标是吃回本,那么胃有限那么每次都仅最贵的吃。

上学时,麻麻说只能带5个苹果,你想带最多,那么选五个苹果你每次都选最大的那个五次下来你就选的最重的那个。

不难发现上面的 策略 虽然没有很强的理论数学依据 ,或者不太好说明。但是 事实规律就是那样 ,并且对于贪心问题大部分都需要 排序 ,还可能会遇到类排序。并且一个物体可能有多个属性,不同问题需要按照不同属性进行排序,操作。

那么我们的 Dijkstra 是如何贪心的呢?对于一个点,求图中所有点的最短路径,如果没有正确的方法胡乱想确实很难算出来,并且如果暴力匹配复杂度呈指数级上升不适合解决实际问题。

那么我们该怎么想呢?

Dijkstra算法的前提:

  1. 首先,Dijkstra处理的是带正权值的 有权图 ,那么,就需要一个 二维数组 (如果空间大用list数组)存储各个点到达( 边 )的权值大小。 (邻接矩阵或者邻接表存储)
  2. 其次,还需要一个 boolean数组 判断那些点已经确定最短长度,那些点没有确定。 int数组 记录距离( 在算法执行过程可能被多次更新 )。
  3. 需要 优先队列 加入 已经确定点的周围点 。每次抛出确定最短路径的那个并且确定最短,直到所有点路径确定最短为止。

简单的概括流程为:

  • 一般从选定点开始抛入优先队列。(路径一般为0), boolean数组 标记0的位置(最短为0) , 然后0 周围连通的点 抛入优先队列中(可能是node类),并把各个点的距离记录到对应数组内( 如果小于就更新,大于就不动,初始第一次是无穷肯定会更新 ),第一次就结束了
  • 从队列中抛出 距离最近 的那个点 B ( 第一次就是0周围邻居 )。这个点距离一定是最近的(所有权值都是正的,点的距离只能越来越长。)标记这个点为 true , 并且将这个点的邻居加入队列 (下一次确定的最短点在前面未确定和这个点邻居中产生),并更新通过 B 点计算各个位置的长度,如果小于则更新!
  • 重复二的操作,直到所有点都确定。

算法实现

package 图论;import java.util.ArrayDeque;import java.util.Comparator;import java.util.PriorityQueue;import java.util.Queue;import java.util.Scanner;public class dijkstra { static class node { int x; //节点编号 int lenth;//长度 public node(int x,int lenth) { this.x=x; this.lenth=lenth; } } public static void main(String[] args) { int[][] map = new int[6][6];//记录权值,顺便记录链接情况,可以考虑附加邻接表 initmap(map);//初始化 boolean bool[]=new boolean[6];//判断是否已经确定 int len[]=new int[6];//长度 for(int i=0;i<6;i ) { len[i]=Integer.MAX_VALUE; } Queue<node>q1=new PriorityQueue<node>(com); len[0]=0;//从0这个点开始 q1.add(new node(0, 0)); int count=0;//计算执行了几次dijkstra while (!q1.isEmpty()) { node t1=q1.poll(); int index=t1.x;//节点编号 int length=t1.lenth;//节点当前点距离 bool[index]=true;//抛出的点确定 count ;//其实执行了6次就可以确定就不需要继续执行了 这句可有可无,有了减少计算次数 for(int i=0;i<map[index].length;i ) { if(map[index][i]>0&&!bool[i]) { node node=new node(i, length map[index][i]); if(len[i]>node.lenth)//需要更新节点的时候更新节点并加入队列 { len[i]=node.lenth; q1.add(node); } } } } for(int i=0;i<6;i ) { System.out.println(len[i]); } } static Comparator<node>com=new Comparator<node>() { public int compare(node o1, node o2) { return o1.lenth-o2.lenth; } }; private static void initmap(int[][] map) { map[0][1]=2;map[0][2]=3;map[0][3]=6; map[1][0]=2;map[1][4]=4;map[1][5]=6; map[2][0]=3;map[2][3]=2; map[3][0]=6;map[3][2]=2;map[3][4]=1;map[3][5]=3; map[4][1]=4;map[4][3]=1; map[5][1]=6;map[5][3]=3; }}

执行结果:

当然,dijkstra算法比较灵活,实现方式也可能有点区别,但是思想是不变的:一个贪心思路。dijkstra执行一次就能够确定一个点,所以只需要执行点的总和次数即可完成整个算法。

收藏
举报
74 条评论
  • 西红柿的前世2020年1月20日

    运筹学

    回复 ⋅ 4条回复1 
  • ddsvueav2020年2月11日

    只知道代码,却根本没能用流畅的语言把算法讲清楚

    回复 ⋅ 1条回复7 
  • 这个,怎么读。。。

    回复 ⋅ 2条回复0 
  • 翼天雪41393535876902020年2月13日

    Dijkstra算法详细(单源最短路径算法) sandag

    回复0 
  • Inpetents9月前

    不断递归,最后不断回溯

    回复0 
(0)

相关推荐

  • OO第三单元作业总结

    OO第三单元作业总结--JML 第三单元的主题是JML规格的学习,其中的三次作业也是围绕JML规格的实现所展开的(虽然感觉作业中最难的还是如何正确适用数据结构以及如何正确地对于时间复杂度进行优化). ...

  • Bellman

    Dijkstra 算法虽然好,但是他不能解决带有负权边的(边的权值为负数)的图,下面我们就来说一下几乎完妹求最短路径的算法Bellman-ford.Bellman-ford算法也非常简单,核心代码只有 ...

  • 学术简报|基于单通道盲源分离算法的局部放电特高频信号去噪方法

    摘要 国网安徽省电力有限公司电力科学研究院的研究人员刘宇舜.程登峰等,在2018年第23期<电工技术学报>上撰文,为有效抑制现场检测局部放电特高频信号背景噪声中的周期性窄带干扰和高斯白噪声 ...

  • 极市直播回放丨第79期-陈鑫:CVPR 2021-​TransT: 基于Transformer的高性能单目标跟踪算法

    相关运算在视觉目标跟踪算法中发挥了重要作用.在跟踪过程中,相关运算通过简单的相似性比较,来完成模板和搜索区域特征的交互,输出一张相似度图来确定目标的位置.然而,相关运算本身是一个局部的线性匹配,导致了 ...

  • 极市直播丨陈鑫:CVPR 2021-​TransT: 基于Transformer的高性能单目标跟踪算法

    一直以来,为让大家更好地了解学界业界优秀的论文和工作,极市已邀请了超过90位技术大咖嘉宾,并完成了78期极市线上直播分享.往期分享请前往bbs.cvmart.net/topics/149或直接阅读原文 ...

  • Dijkstra算法(迪杰斯特拉算法)

    对比算法好坏需要考虑的因素 执行算法所耗费的时间 执行算法所耗费的存储空间 Dijkstra算法(迪杰斯特拉算法) 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959年提出的,是从一个顶点到其余各 ...

  • 弗洛伊德(Floyd)算法求图的最短路径

    弗洛伊德基本思想 弗洛伊德算法作为求最短路径的经典算法,其算法实现相比迪杰斯特拉等算法是非常优雅的,可读性和理解都非常好. 基本思想: 弗洛伊德算法定义了两个二维矩阵: 矩阵D记录顶点间的最小路径 例 ...

  • 算法创作 | 单链表插入问题解决方法

    问题描述 如何利用尾插法实现单链表中元素的插入? 如: 如何利用前插法实现单链表中元素的插入? 如: 解决方案 利用尾插法进行元素的插入:将需要插入的结点的前一个结点的next地址改成需要插入的结点 ...

  • 算法创作|单链表的基本操作

    问题描述 单链表是链表的一种,是一种链式存取的数据结构.用一组地址任意的存储单元存放线性表中的数据元素,链表中的数据是以结点(node)来表示的,每个结点的构成包括数据域(date)和指针域(next ...

  • 算法创作|单链表基本操作问题解决方法

    问题描述单链表:用文字描述要解决的问题是什么.用P表示head,也即是头指针,设计算法让P指向任何一个元素.示例:让P指向第n个元素.解决方案p=headfork in range(n):p=p.ne ...

  • 卡内基梅隆大学的研究人员提出新的源定位算法: SilenceMap,寻找大脑的静默区域

    大脑是最重要的器官之一.它们为整个身体提供调度指示,让我们能够与世界互动.因此,快速检测大脑活动的变化是很重要的.一种可能导致永久性损伤的危险变化是神经静默(neural silence)[注:这个词 ...