基于STL优先队列和邻接表的dijkstra算法
首先说下STL优先队列的局限性,那就是只提供入队、出队、取得队首元素的值的功能,而dijkstra算法的堆优化需要能够随机访问队列中某个节点(来更新源点节点的最短距离)。
看似可以用vector配合make_heap/push_heap/pop_heap来实现这个功能,实际上手动实现就会发现问题所在。比如在dist[v] > dist[u] + cost(u,v)时,需要更新dist[v],然后重新确定v在vector的位置,需要使用push_heap,这样问题就出现了。
v又在vector的哪个位置呢?只有在vector中一个个查找,除非在之前维护最小(距离)堆的时候,每次交换元素,记录元素的位置变化,也就是用int pos[V];(V为顶点数,下面不再重复说明)来记录,每次push_heap和pop_heap使堆的元素交换的时候(swap(heap[i], heap[j];)还要顺便交换位置(swap(pos[i], pos[j]);)
而仅仅是用STL提供的接口是无法实现的,只有从头造轮子。
于是有个折中的方法,那就是仍然使用优先队列。只是在更新点v的最短距离时,把点v重新加入队列中,而队列中已经存在的v无法访问就继续搁着。
也就是说队列中有2个点v,一个是用更新后的距离进行堆操作的,一个是用更新前的距离进行堆操作的。
首先我不是用while (!q.empty())判断终止条件的,而是照着书上的for (int i = 0; i < V; i++)判断,这样问题就在于,可能点v已经出队了(代表着已经确定源点到点v的最短路径),此时若点v出队则需要跳过。
书上之所以只循环V-1次是因为书上用的堆优化,不会像我这样重复添加某元素到堆中,而是更新堆中元素的权值并移动位置。由于每次循环都能确定源点到某个点的最短路径,所以只需要V-1次足矣。
而退而求其次的直接用优先队列的做法也可以直接循环V-1次,只不过每次循环开头要判断队首元素是否已经确定了最短距离,若是则弹出,一直到队首元素是未确定最短距离。不如while (!q.empty())加continue简洁(见下面核心代码)
auto comp = [](int v1, int v2) { return dist[v1] > dist[v2]; };
priority_queue<int, vector<int>, decltype(comp)> q(comp);
dist[v0] = 0;
q.push(v0); while (!q.empty()) {
int u = q.top();
q.pop();
if (vis[u]) // 已经求过v0到u的最短路径
continue; vis[u] = true;
for (auto& e : adjList[u]) {
int v = e.adjID;
if (!vis[v] && dist[v] - dist[u] > e.len) {
dist[v] = dist[u] + e.len;
pre[v] = u;
q.push(v);
}
}
}
其他代码就不贴了,对其中用到的一些全局变量做个说明。
注意如果dist是定义在dijkstra函数体内的,lambda表达式要捕获dist的引用,即auto comp = [&dist](后面不变)
vector<AdjList> adjList; // 邻接表, 预先读取了数据
// AdjList是STL容器Container<T>的别名(Container可以是vector或list或deque),T是AdjEdge(邻接边), 定义如下(省略了构造函数)
struct AdjEdge {
int adjID; // 邻接点的ID
int len; // 邻接边的长度
};
vector<int> dist(V, INT_MAX); // 最短距离
vector<int> pre(V, -1); // 最短路径上的前1个节点号
deque<bool> vis(V, false); // 若求出了最短距离则置为true
基于STL优先队列和邻接表的dijkstra算法的更多相关文章
- 邻接表实现Dijkstra算法以及DFS与BFS算法
//============================================================================ // Name : ListDijkstr ...
- 做了一道跑大数据的最短路挂了,基于vector的二维模拟邻接表实现Dijkstra算法(*【模板】)
代码: #include <stdio.h> #include <string.h> #include <string> #include <vector&g ...
- C++ 基于STL的演讲比赛流程管理系统(sort算法+小型算法(accumulate)+内建函数对象+string字符串拼接+字符串截取+多个容器基础操作+与用户交互+文件的读写+保存+重建+整体文件数据的清空)
1 /* 2 比赛规则: 3 学校举行一演讲比赛,共12个人参加,比赛两轮,第一轮为淘汰赛 第二轮为决赛 4 每名选手都有对应的编号:如10001~10012 5 比赛方式:分组比赛 每组6人 6 第 ...
- POJ 1511 Invitation Cards(Dijkstra(优先队列)+SPFA(邻接表优化))
题目链接:http://poj.org/problem?id=1511 题目大意:给你n个点,m条边(1<=n<=m<=1e6),每条边长度不超过1e9.问你从起点到各个点以及从各个 ...
- 基于STL的字典生成模块-模拟搜索引擎算法的尝试
该课题来源于UVA中Searching the Web的题目:https://vjudge.net/problem/UVA-1597 按照题目的说法,我对按照特定格式输入的文章中的词语合成字典,以满足 ...
- 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(二)
一.基于邻接表的Dijkstra算法 如前一篇文章所述,在 Dijkstra 的算法中,维护了两组,一组包含已经包含在最短路径树中的顶点列表,另一组包含尚未包含的顶点.使用邻接表表示,可以使用 BFS ...
- 最小生成树Prim算法(邻接矩阵和邻接表)
最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...
- 第6章 图的学习总结(邻接矩阵&邻接表)
我觉得图这一章的学习内容更有难度,其实图可以说是树结构更为普通的表现形式,它的每个元素都可以与多个元素之间相关联,所以结构比树更复杂,然而越复杂的数据结构在现实中用途就越大了,功能与用途密切联系,所以 ...
- 最短路径 | 深入浅出Dijkstra算法(一)
参考网址: https://www.jianshu.com/p/8b3cdca55dc0 写在前面: 上次我们介绍了神奇的只有五行的 Floyd-Warshall 最短路算法,它可以方便的求得任意两点 ...
随机推荐
- angularJS----filter
angularJS过滤器 过滤器(filter)正如其名,作用就是接收一个输入(隐式的接收数据源),通过某个规则进行处理,然后返回处理后的结果.主要用在数据的格式化上,例如获取一个数组中的子集,对数组 ...
- linux中的/usr,/var,/opt目录详解
转自:http://it.greenblogs.org/archives/2008/20113.shtml/ /usr文件系统 /usr 文件系统经常很大,因为所有程序安装在这里. /usr 里的所 ...
- 在Linux下设置定时任务(每分钟执行一次特定的shell脚本)
在当前用户下,开始编辑定时任务 crontab -e 按键 i 进入编辑模式 输入下述命令 */ * * * * sh /***/*****.sh 然后按键 Esc 退出编辑模式,再输入 wq 保存退 ...
- Http权威指南(cookie以及web认证机制)
其实对于cookie,想必大家都不陌生,cookie目前主要用于客户端的识别技术. 说到客户端识别技术,就不得不说一个登录态的问题了.登录态顾名思义,用于验证用户的登录与否. 1.登录态 对于PC端网 ...
- GPU编程自学3 —— CUDA程序初探
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- CSS样式让元素填充剩余部分为自己的高度或宽度
#nav { background-color: #85d989; width: 100%; height: 50px; } #content { background ...
- IOS开发 arc与非Arc代码的区别
是属于ios开发中的内存管理问题:在这我简要概述一下,详细讲的话内容挺多,而且是作为一个ios开发人员,或ios开发爱好者,这是必须了解的:Objective-c中提供了两种内存管理机制MRC(Man ...
- Chrome 插件下载
这里推荐几个下载chrome扩展的网站 http://www.cnplugins.com/index.html 分类全,没有搜索 http://www.chromein.com/ 有搜索,推荐使用 h ...
- c语言符号常量与常变量的区别?
<blockquote>定义符号常量:#define PI 3.1415926 //注意后面没有分号 定义常变量 :const float PI=3.1415 ...
- HDU1576 A/B
暴力出奇迹,我就知道没取余那么正当,肯定有什么奇淫怪巧,果然5分钟A掉. #include<cstdio> #include<cstdlib> #include<iost ...