Dijkstra算法堆/优先队列优化

  • 前言
  • 额外知识简介
    • 堆与优先队列
    • STL库
    • 重载
  • Dijkstra分析及优化
    • 分析优化
    • 代码实现
      • 存储结构
        • 优先队列
      • 函数
        • 初始化
        • 添加边
        • Dijkstra
      • 主函数
  • 后记

前文:Dijkstra算法&&邻接表数组

前言

​ 1、本文中所采用的存储结构依然是邻接表数组,只是较上一篇文章中的结构稍微发生了一些变化,但本质是一样的,若不懂可参考前文;

​ 2、本文将涉及到堆/优先队列、STL库、运算符重载等额外知识,若不了解可百度或google,文中只会提及其使用而不会深入介绍;

​ 3、代码仍将采用C++实现,较前文含有更多的C++特有内容,需先了解这些操作才能看懂本文的代码;

​ 4、若对本文存在疑问、意见或建议,欢迎评论及与我本人联系。

额外知识简介

堆与优先队列

​ 首先,队列是一种数据结构,堆也是一种数据结构。普通的队列我们可以通过顺序表,链表的方式来实现。同样,优先队列我们通常使用堆这种数据结构来实现。因为优先队列中的元素具有优先级,每次出队的是优先级最高的元素,而堆恰好拥有这种特性——所有父节点的优先级均高于子节点。因此我们可以通过堆这种手段来实现优先队列。在这个层面上来说,Dijkstra算法的优先队列优化就是堆优化,即在Dijkstra算法运行的过程中维护一个优先队列。

STL库

​ STL库是C++的独有内容,这个库中存放了大量的数据结构模板,如vector、queue、stack、map等等,通过对STL库的调用,不仅可以提高代码的可读性和简洁性,也大大减小了出错的可能性(前提是要正确使用),实乃一大捷径。/滑稽

重载

​ 重载也是C++的独有内容,重载可以使一些符号和函数拥有多种功能,前提是参数类型和数量不能完全相同,与他们的返回值和函数内容无关。举个栗子,假如我们在一个程序中定义了一个函数plus,那么plus(int a,int b)与 plus(int a,int b, int c)和plus(int a,long long b)这三个函数是可以同时存在的,但plus(int a,int b)与 plus(int c,int d)是不能同时存在的,因为编译器无法区分这两个函数,你调用函数的时候系统就晕了,不知道该调用哪个,因此这样是不合法的重载,无法通过编译。

Dijkstra分析及优化

分析优化

​ 通过前文,我们已经详细了解了Dijkstra算法的运行过程,相信聪明的小伙伴们已经在其中发现了问题。这里我就直接切入正题。已知Dijkstra算法每次在集合B中寻找能够加入集合A的顶点的时候,都要将符合条件的边进行遍历,即前文中的如下循环

min=inf;//记录当前情况下长度最小的路径
for (j=1;j<=n;j++)
{if (!book[j]&&dis[j]<min){min=dis[j];p=j;//记录最短路径的终点/弧头}
}
book[p]=true;//将最短路径的终点/弧头加入集合

​ 当边较多的时候,该循环会带来较大的时间复杂度。那么有没有什么办法对它进行优化呢?当然是有啦!可不可以直接得到那条最短的边呢?当然是可以啦!在这里我们可以维护一个优先队列,队列中存放的是点(额外定义的一种数据类型),该点离顶点距离越小优先级越高。这样每次取队首元素,就可以得到当前状态下距离起点距离最短的点,并让其出队。若该点已在集合A中,则继续出队,否则将其加入集合A,并以该点为中介点进行松弛操作。(若此点i不在集合A中,则dis[i]表示起点到点i的距离或起点到点i经过松弛之后的距离,若点i不在集合A中且其位于队首位置,那么它到集合A中某点的距离一定是最小的,这样便可保证我们取队首元素就能取到算法中描述的“最短边”)如此一来便可以大大减小算法的时间复杂度。

代码实现

存储结构

struct Edge//定义边的结构体
{int to;//弧头int value;//权值int next;//“链域”Edge(int a=0,int b=inf,int c=0):to(a),value(b),next(c) {}//重载构造函数//即当定义一个Edge类型的变量时,立即初始化为a,b,c的默认值0,inf,0(此处inf值为0x3f3f3f3f)
}e[M2];

typedef struct Point//定义顶点的结构体类型
{int num;//顶点编号int dist;//起点到该顶点的距离Point(int a=0,int b=0):num(a),dist(b) {}//重载构造函数,含义同上inline bool operator < (const Point& b) const//重载<{return dist>b.dist;}//若顶点a的dist值大于顶点b的dist值,则a的优先级低于b
}Point;

优先队列

priority_queue <Point> q;

函数

初始化

void init()
{cnt=0;memset(head,-1,sizeof(head));return;
}

添加边

inline void add(int a,int b,int c)
{e[cnt].to=b;e[cnt].value=c;e[cnt].next=head[a];head[a]=cnt++;return;
}

Dijkstra

void dijkstra(int st)//st为起点
{int i;Point p;for (i=1;i<=n;++i)dis[i]=inf;//初始化起点到各点距离dis[st]=0;p.num=st;//起点编号p.dist=0;//起点与自己距离为0q.push(p);//将起点加入优先队列while (!q.empty()){int cur=q.top().num;//本次循环中距离最短的边的终点编号q.pop();//出队if (vis[cur])continue;//若此点已确定最短距离则跳过此点并进行下一次循环vis[cur]=1;//本次循环将确定该点的最短距离for (i=head[cur];i!=-1;i=e[i].next){int to=e[i].to;//本次循环中的目标点if (dis[to]>e[i].value+dis[cur]&&!vis[to]){dis[to]=dis[cur]+e[i].value;//松弛p.num=to;p.dist=dis[to];q.push(p);//将到起点距离变短的点加入队列}}}for (i=1;i<=n;i++)cout<<dis[i]<<" "<<endl;//输出起点到各顶点的最短距离return;
}

主函数

int main()
{ios::sync_with_stdio(false);int i,x,y,z;cin>>n>>m;//n个点m条边init();for (i=0;i<m;i++){cin>>x>>y>>z;add(x,y,z);add(y,x,z);}dijkstra(1);//以1为起点return 0;
}

可采取如下数据验证

6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4

运行结果如下

0
1
8
4
13
17

后记

此种方式优化后,虽然大大节省了时间开销,但是使用了优先队列,导致内存开销增大,当边数很多的时候,可能会爆内存。在此基础上依然可以进行优化,利用配对堆等方式缩小内存开销。

Dijkstra算法堆/优先队列优化相关推荐

  1. PAT甲级1003 Emergency Dijkstra算法(堆优化版/朴素版)

    前言   最近花了很多的时间在写JAVA项目上面,疏忽了算法和数据结构的学习.最近突然醒悟基础更为重要,打算从今天开始每天抽出一些时间做下PAT甲级的题目.现有题库的前两题很简单,从第三题开始吧. 题 ...

  2. 【Dijkstra算法】未优化版+优先队列优化版

    https://blog.csdn.net/YF_Li123/article/details/74090301 Dijkstra算法伪代码://G为图:数组d为源点到达各点的最短路径长度,s为起点 D ...

  3. 03 最短路 dijkstra算法spfa算法floyd算法(附带实例代码) 图论-1

    文章目录 最短路 邻接表的图如下 邻接矩阵如下图 链表实现邻接表实现代码 单源最短路径 Dijkstra 算法 朴素版本 Dijkstra 实现代码 堆优化的dijkstra算法代码实现 Bellma ...

  4. Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解

    1 /* 2 Dijkstra算法用优先队列来实现,实现了每一条边最多遍历一次. 要知道,我们从队列头部找到的都是到 3 已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 ...

  5. 知识点二十四:最短路径——Dijkstra 算法

    前言 像 Google 地图.百度地图.高德地图这样的地图软件,你只需要输入起始.结束地址,地图就会给你规划一条最优出行路线.这里说的最优路线,有很多种定义,比如最短路线.最少用时路线.最少红绿灯路线 ...

  6. 最短路径——Dijkstra算法以及二叉堆优化(含证明)

    一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...

  7. dij算法堆优化_迪杰斯特拉算法(Dijkstra) (基础dij+堆优化) BY:优少

    算法实现步骤: a.初始时,只包括源点,即S = {v},v的距离为0.U包含除v以外的其他顶点,即:U ={其余顶点},若v与U中顶点u有边,则(u,v)为正常权值,若u不是v的出边邻接点,则(u, ...

  8. dij算法堆优化_迪杰斯特拉算法(Dijkstra) (基础dij+堆优化) BY:优少(示例代码)...

    算法实现步骤: a.初始时,只包括源点,即S = {v},v的距离为0.U包含除v以外的其他顶点,即:U ={其余顶点},若v与U中顶点u有边,则(u,v)为正常权值,若u不是v的出边邻接点,则(u, ...

  9. dijkstra算法及其堆优化

    dijkstra算法及其堆优化 (个人笔记写给自己看的) 数据结构:链式前向星,优先队列 dijkstra算法: vis数组初始化为0,dis数组初始化为inf(很大的值如:0x7fffffff),设 ...

最新文章

  1. java 中pc寄存器的作用_既然有PC寄存器,栈帧里的返回地址的作用是什么?
  2. alter table add column多个字段_WordPress 在文章列表快速编辑中编辑自定义字段
  3. Linux命令之 umount -- 卸载文件系统
  4. 从pheatmap无缝迁移至ComplexHeatmap
  5. python aiompq集群_国内首款基于AIO(异步IO)支持集群的高性能开源WebSocket服务器 宝贝鱼 CshBBrain V4.0 发布...
  6. phalcon index.php,Phalcon环境搭建与项目开发
  7. Python程序设计学习笔记-概述
  8. 高质量 Android 开发框架 LoonAndroid 详解
  9. lesson 7 strategies for efficient CUDA programming
  10. x264源代码简单分析:编码器主干部分-2
  11. 游戏开发之C++对C的扩展(C++基础)
  12. csharp添加引用路径_C# 在Word中添加Latex 数学公式和符号
  13. 计算机打印不了测试纸,win10系统打印机无法打印测试页的解决办法
  14. 教务管理系统设计与实现
  15. 【Word】Word公式导出PDF后出现井号括号#()错误
  16. Vue路由守卫(通俗易懂)
  17. E - Help Hanzo(LightOJ 1197)
  18. 简单服务发现协议SSDP【转】
  19. JavaWeb基础5——HTTP,TomcatServlet
  20. expect的基本用法

热门文章

  1. linux 内核协议栈 UDP数据报校验和
  2. 网狐6603棋牌游戏源码.rar
  3. Zeroc Ice 学习笔记--IceBox
  4. 从Noob开始学习python/pyqt5(1)环境安装,工程搭建与打包exe
  5. 网络斗地主游戏的完整设计与实现(一)项目的基本结构
  6. 第十三届蓝桥杯A组省赛填空程序真题集
  7. Qt Symbian 手机环境搭建
  8. 你是我最熟悉的陌生人。。。
  9. c++ 获取windows剪切板的富文本
  10. 计算机二级VEP考试内容,计算机二级VEP考点