C++ dijkstra 最短路径算法
一:概述
Dijkstra 算法是由 荷兰计算机科学家 Edsger W. Dijkstra(艾兹赫尔·戴克斯特拉) 在 1956 年 发明的,并于 1959 年正式发表。Dijkstra 算法 是一种用于计算图中 单源最短路径(Single-Source Shortest Path) 的经典算法。也就是说,它可以求出从一个起点到图中所有其他点的最短路径。
Dijkstra 算法的核心思想是:贪心策略 —— 每次总是选择当前已知的距离起点最近的未访问节点,并尝试更新其邻居的最短路径。
算法步骤(以邻接表 + 最小堆实现为例):
初始化所有点到源点的距离为 ∞(无穷大),源点到自身为 0;
使用 最小堆(优先队列) 选择当前距离源点最短的节点;
对其所有邻居节点尝试 “松弛”操作(即更新邻居最短路径);
将更新后的节点重新加入堆中;
重复步骤 2~4,直到所有点都被访问或目标点被访问;
返回目标点的距离。
二:实现
#include <cassert>
#include <iostream>
#include <limits>
#include <queue>
#include <utility>
#include <vector>constexpr int64_t MAX = std::numeric_limits<int64_t>::max();namespace graph {using adjacency_list = std::vector<std::vector<std::pair<int, int>>>;/*** @brief 向图中添加一条有向边* @param adj 图的邻接表* @param u 起点编号(1-based)* @param v 终点编号(1-based)* @param w 边的权重*/void add_edge(adjacency_list& adj, int u, int v, int w) {adj[u - 1].emplace_back(v - 1, w);}/*** @brief 使用 Dijkstra 算法计算起点 s 到终点 t 的最短路径长度* @param adj 图的邻接表* @param s 起点编号(0-based)* @param t 终点编号(0-based)* @return 最短路径长度;不可达时返回 -1*/int dijkstra(const adjacency_list& adj, int s, int t) {int n = static_cast<int>(adj.size());std::vector<int64_t> dist(n, MAX);// 优先级队列(最小堆):元素为 pair<距离, 顶点编号>std::priority_queue<std::pair<int64_t, int>,std::vector<std::pair<int64_t, int>>,std::greater<>>pq;dist[s] = 0;pq.emplace(0, s);while (!pq.empty()) {auto [current_dist, u] = pq.top();pq.pop();// 如果当前距离大于已知距离,说明此条路径已过时,跳过if (current_dist > dist[u]) continue;// 松弛操作for (const auto& [v, weight] : adj[u]) {if (current_dist + weight < dist[v]) {dist[v] = current_dist + weight;pq.emplace(dist[v], v);}}}return dist[t] == MAX ? -1 : static_cast<int>(dist[t]);}/*** @brief 内置测试函数*/int run_tests() {std::cout << "Running predefined tests...\n";{std::cout << "Test 1...\n";adjacency_list adj(5);add_edge(adj, 1, 2, 3);add_edge(adj, 1, 3, 8);add_edge(adj, 2, 4, 2);add_edge(adj, 3, 5, 10);add_edge(adj, 4, 5, 1);assert(dijkstra(adj, 0, 4) == 6); // 1->2->4->5 总权重 3+2+1=6std::cout << "Test 1 passed.\n";}{std::cout << "Test 2...\n";adjacency_list adj(4);add_edge(adj, 1, 2, 1);add_edge(adj, 2, 3, 4);add_edge(adj, 3, 4, 1);add_edge(adj, 1, 4, 10);assert(dijkstra(adj, 0, 3) == 6); // 1->2->3->4 总权重 1+4+1=6std::cout << "Test 2 passed.\n";}{std::cout << "Test 3 (Unreachable)...\n";adjacency_list adj(3);add_edge(adj, 1, 2, 5);// 3号节点孤立,无法到达assert(dijkstra(adj, 0, 2) == -1); // 1->3 不可达std::cout << "Test 3 passed.\n";}std::cout << "All tests passed successfully.\n";return 0;}} // namespace graph