首先说下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算法的更多相关文章

  1. 邻接表实现Dijkstra算法以及DFS与BFS算法

    //============================================================================ // Name : ListDijkstr ...

  2. 做了一道跑大数据的最短路挂了,基于vector的二维模拟邻接表实现Dijkstra算法(*【模板】)

    代码: #include <stdio.h> #include <string.h> #include <string> #include <vector&g ...

  3. C++ 基于STL的演讲比赛流程管理系统(sort算法+小型算法(accumulate)+内建函数对象+string字符串拼接+字符串截取+多个容器基础操作+与用户交互+文件的读写+保存+重建+整体文件数据的清空)

    1 /* 2 比赛规则: 3 学校举行一演讲比赛,共12个人参加,比赛两轮,第一轮为淘汰赛 第二轮为决赛 4 每名选手都有对应的编号:如10001~10012 5 比赛方式:分组比赛 每组6人 6 第 ...

  4. POJ 1511 Invitation Cards(Dijkstra(优先队列)+SPFA(邻接表优化))

    题目链接:http://poj.org/problem?id=1511 题目大意:给你n个点,m条边(1<=n<=m<=1e6),每条边长度不超过1e9.问你从起点到各个点以及从各个 ...

  5. 基于STL的字典生成模块-模拟搜索引擎算法的尝试

    该课题来源于UVA中Searching the Web的题目:https://vjudge.net/problem/UVA-1597 按照题目的说法,我对按照特定格式输入的文章中的词语合成字典,以满足 ...

  6. 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(二)

    一.基于邻接表的Dijkstra算法 如前一篇文章所述,在 Dijkstra 的算法中,维护了两组,一组包含已经包含在最短路径树中的顶点列表,另一组包含尚未包含的顶点.使用邻接表表示,可以使用 BFS ...

  7. 最小生成树Prim算法(邻接矩阵和邻接表)

    最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...

  8. 第6章 图的学习总结(邻接矩阵&邻接表)

    我觉得图这一章的学习内容更有难度,其实图可以说是树结构更为普通的表现形式,它的每个元素都可以与多个元素之间相关联,所以结构比树更复杂,然而越复杂的数据结构在现实中用途就越大了,功能与用途密切联系,所以 ...

  9. 最短路径 | 深入浅出Dijkstra算法(一)

    参考网址: https://www.jianshu.com/p/8b3cdca55dc0 写在前面: 上次我们介绍了神奇的只有五行的 Floyd-Warshall 最短路算法,它可以方便的求得任意两点 ...

随机推荐

  1. Spring整合Hibernate:1、annotation方式管理SessionFactory

    1.在applicationContext.xml文件中初始化SessionFactory(annotation方式) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 ...

  2. 《利用Python进行数据分析》笔记---第4章NumPy基础:数组和矢量计算

    写在前面的话: 实例中的所有数据都是在GitHub上下载的,打包下载即可. 地址是:http://github.com/pydata/pydata-book 还有一定要说明的: 我使用的是Python ...

  3. 自定义view:view的绘制流程

    1.view的绘制流程 当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理.绘制是从根节点开始,对布局树进行 measure 和 draw. ...

  4. linux给一个文件夹开启权限

    假如要给一个叫做xiaobang的文件夹权限,CD到这一级目录 chmod -R 777 xiaobang

  5. python kd树 搜索 代码

    kd树就是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构,可以运用在k近邻法中,实现快速k近邻搜索.构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,依次选择坐标轴对空间 ...

  6. JAVA多线程----用--进阶--》网络编程1

    http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 一个服务器端一般都需要同时为多个客户端提供通讯,如果需要同时支持多个客 ...

  7. Failed to read schema document

    转自:http://eric-yan.iteye.com/blog/1908470 问题描述: web项目web.xml编译错误: schema_reference.4: Failed to read ...

  8. erl_0020 《面对软件错误构建可靠的分布式系统》读书笔记001 “面向并发COPL”

    在现实世界中,顺序化的(sequential)活动非常罕见.当我们走在大街上的时候,如果只看到一件事情发生的话我们一定会感到不可思议,我们期望碰到许多同时进行的活动. 如果我们不能对同时发生的众多事件 ...

  9. BZOJ:5092 [Lydsy1711月赛]分割序列(贪心&高维前缀和)

    Description 对于一个长度为n的非负整数序列b_1,b_2,...,b_n,定义这个序列的能量为:f(b)=max{i=0,1,...,n}((b_1 xor b _2 xor...xor ...

  10. C#/.NET 中推荐的 Dispose 模式的实现

    如果你觉得你的类需要实现 IDisposable 接口,还是需要注意一些坑的.不过前人准备了 Dispose 模式 供我们参考,最大程度避免这样的坑. C#程序中的 Dispose 方法,一旦被调用了 ...