首先说下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. 转:基于Flume的美团日志收集系统(一)架构和设计

    美团的日志收集系统负责美团的所有业务日志的收集,并分别给Hadoop平台提供离线数据和Storm平台提供实时数据流.美团的日志收集系统基于Flume设计和搭建而成. <基于Flume的美团日志收 ...

  2. python面试题包含基础和Linux操作以及数据库相关

    今天面试了一家公司,感觉表现的不是很好,记录一下面试的试题. python基础部分 python 是一门什么样的语言面向对象的语言有那些,python的面向对象和Java面向对象的区别 Python是 ...

  3. 多线程-Thread、Runnable 创建线程和调用过程分析

    创建线程的两种方式: 1:创建Thread类的子类 ---基于继承的技术 . 2:以Runnable接口实例为构造参数直接通过new  创建 Thread 实例.---基于组合的技术. public ...

  4. qml 关于鼠标穿透的问题

    最近在开发过程中,遇到了鼠标穿透的问题.结合网上给予的方法,都试了一圈,在这里总结一下: import QtQuick 2.9import QtQuick.Window 2.2import QtQui ...

  5. 【Shell脚本】逐行处理文本文件

    经常会对文体文件进行逐行处理,在Shell里面如何获取每行数据,然后处理该行数据,最后读取下一行数据,循环处理.有多种解决方法如下: 1.通过read命令完成. read命令接收标准输入,或其他文件描 ...

  6. Shell 命令行 从日志文件中根据将符合内容的日志输出到另一个文件

    Shell 命令行 从日志文件中根据将符合内容的日志输出到另一个文件 前面我写了一篇博文Shell 从日志文件中选择时间段内的日志输出到另一个文件,利用循环实现了我想要实现的内容. 但是用这个脚本的同 ...

  7. 老男孩Linux运维期中架构

  8. iOS怎么来实现关闭自动锁屏

    怎么来设置[UIApplication sharedApplication]   idleTimerDisabled 属性来控制自动锁屏的效果 // 把设置idleTimerDisabled的代码放到 ...

  9. Visual Studio Community 版本过期

    /********************************************************************* * Visual Studio Community 版本过 ...

  10. 日志组件logback的介绍及配置使用方法(一)

    一.logback的介绍 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分成三个模块:logback-core,logback- classic和logback-acc ...