Dijkstra算法堆/优先队列优化
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算法堆/优先队列优化相关推荐
- PAT甲级1003 Emergency Dijkstra算法(堆优化版/朴素版)
前言 最近花了很多的时间在写JAVA项目上面,疏忽了算法和数据结构的学习.最近突然醒悟基础更为重要,打算从今天开始每天抽出一些时间做下PAT甲级的题目.现有题库的前两题很简单,从第三题开始吧. 题 ...
- 【Dijkstra算法】未优化版+优先队列优化版
https://blog.csdn.net/YF_Li123/article/details/74090301 Dijkstra算法伪代码://G为图:数组d为源点到达各点的最短路径长度,s为起点 D ...
- 03 最短路 dijkstra算法spfa算法floyd算法(附带实例代码) 图论-1
文章目录 最短路 邻接表的图如下 邻接矩阵如下图 链表实现邻接表实现代码 单源最短路径 Dijkstra 算法 朴素版本 Dijkstra 实现代码 堆优化的dijkstra算法代码实现 Bellma ...
- Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解
1 /* 2 Dijkstra算法用优先队列来实现,实现了每一条边最多遍历一次. 要知道,我们从队列头部找到的都是到 3 已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 ...
- 知识点二十四:最短路径——Dijkstra 算法
前言 像 Google 地图.百度地图.高德地图这样的地图软件,你只需要输入起始.结束地址,地图就会给你规划一条最优出行路线.这里说的最优路线,有很多种定义,比如最短路线.最少用时路线.最少红绿灯路线 ...
- 最短路径——Dijkstra算法以及二叉堆优化(含证明)
一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...
- dij算法堆优化_迪杰斯特拉算法(Dijkstra) (基础dij+堆优化) BY:优少
算法实现步骤: a.初始时,只包括源点,即S = {v},v的距离为0.U包含除v以外的其他顶点,即:U ={其余顶点},若v与U中顶点u有边,则(u,v)为正常权值,若u不是v的出边邻接点,则(u, ...
- dij算法堆优化_迪杰斯特拉算法(Dijkstra) (基础dij+堆优化) BY:优少(示例代码)...
算法实现步骤: a.初始时,只包括源点,即S = {v},v的距离为0.U包含除v以外的其他顶点,即:U ={其余顶点},若v与U中顶点u有边,则(u,v)为正常权值,若u不是v的出边邻接点,则(u, ...
- dijkstra算法及其堆优化
dijkstra算法及其堆优化 (个人笔记写给自己看的) 数据结构:链式前向星,优先队列 dijkstra算法: vis数组初始化为0,dis数组初始化为inf(很大的值如:0x7fffffff),设 ...
最新文章
- java 中pc寄存器的作用_既然有PC寄存器,栈帧里的返回地址的作用是什么?
- alter table add column多个字段_WordPress 在文章列表快速编辑中编辑自定义字段
- Linux命令之 umount -- 卸载文件系统
- 从pheatmap无缝迁移至ComplexHeatmap
- python aiompq集群_国内首款基于AIO(异步IO)支持集群的高性能开源WebSocket服务器 宝贝鱼 CshBBrain V4.0 发布...
- phalcon index.php,Phalcon环境搭建与项目开发
- Python程序设计学习笔记-概述
- 高质量 Android 开发框架 LoonAndroid 详解
- lesson 7 strategies for efficient CUDA programming
- x264源代码简单分析:编码器主干部分-2
- 游戏开发之C++对C的扩展(C++基础)
- csharp添加引用路径_C# 在Word中添加Latex 数学公式和符号
- 计算机打印不了测试纸,win10系统打印机无法打印测试页的解决办法
- 教务管理系统设计与实现
- 【Word】Word公式导出PDF后出现井号括号#()错误
- Vue路由守卫(通俗易懂)
- E - Help Hanzo(LightOJ 1197)
- 简单服务发现协议SSDP【转】
- JavaWeb基础5——HTTP,TomcatServlet
- expect的基本用法