一、代码实例
先欣赏一下优美的算法代码
#include <iostream>
#include <vector>
#include <queue>
#include <limits>
#include <unordered_map>
using namespace std;
// 定义图的边结构
struct Edge {
int to; // 边的目标顶点
int weight; // 边的权重
};
// 定义优先队列中的元素
struct CompareDist {
bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
return a.second > b.second;
}
};
//pair<int, int>,第一个 int 表示顶点,第二个 int 表示从源点到该顶点的距离。
// Dijkstra算法
void dijkstra(const vector<vector<Edge>>& graph, int start, vector<int>& dist) {
//dist 数组用于存储从源点到各个顶点的最短距离,
int n = graph.size();
dist.assign(n, numeric_limits<int>::max()); // 初始化距离数组为无穷大
dist[start] = 0; // 起点到自身的距离为0
// 优先队列,存储 (顶点, 距离)
priority_queue<pair<int, int>, vector<pair<int, int>>, CompareDist> pq;
pq.push({start, 0});
while (!pq.empty()) {
int u = pq.top().first;//当前的顶点
int d = pq.top().second;//当前距离
pq.pop();
// 如果当前距离大于已知最短距离,跳过
if (d > dist[u]) continue;
// 遍历当前顶点的所有邻接顶点
for (const auto& edge : graph[u]) {//graph[u]也是个数组,
int v = edge.to;//边的目标顶点
int weight = edge.weight;
// 如果找到更短的路径,更新距离并加入优先队列
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.push({v, dist[v]});
}
}//1
}
}
/*
遍历顶点 u = 0 的所有邻接顶点。graph[0] 中有到顶点1和顶点2的边。
对于到顶点1的边,v = 1,weight = 10,由于 dist[0] + 10 = 0 + 10 = 10 < dist[1](此时 dist[1] 是无穷大),
所以更新 dist[1] = 10,并将 {1, 10} 加入优先队列 pq。对于到顶点2的边,v = 2,weight = 3,
因为 dist[0] + 3 = 0 + 3 = 3 < dist[2](此时 dist[2] 是无穷大),
更新 dist[2] = 3,并将 {2, 3} 加入优先队列 pq。此时优先队列 pq 中有两个元素 {2, 3} 和 {1, 10}。
*/
这段例子可以放在for循环代码后的注解1处,方便一会儿理解,如果觉得麻烦,就在文章直接看。
二、对代码一些东西的解释
1、pair<int,int>:
-
std::pair是 C++ 标准库中的一个模板类,用于存储两个不同类型的值。它定义在<utility>头文件中。 -
一个
std::pair对象包含两个成员变量:first和second,分别表示第一个和第二个元素。
这里就是借来存储东西的,变量名.first/.second,就行,咱们这里用的是两个int,所以pair就是同时存两个int类型数据的;
2、numeric_limits<int>::max():
numeric_limits<int>::max()是 C++ 标准库中用于获取int类型能够表示的最大值的函数。它来自<limits>头文件中的std::numeric_limits模板类。
3、 vector<vector<Edge>>& graph:
就是存储Edge类型的二维数组,变量名叫graph,至于vector,是C++库函数中的一个类似快捷创建动态数组的一个函数名,具体用法可以AI搜一下。
4、struct CompareDist:
- 自定义一个比较器结构体,用于在优先队列(
priority_queue)中自定义元素的比较方式。在 Dijkstra 算法中,我们通常需要一个最小堆来存储待处理的顶点,并且按照从源点到这些顶点的距离从小到大进行排序,CompareDist结构体正是为了实现这一点。
5、priority_queue<pair<int, int>, vector<pair<int, int>>, CompareDist> pq:
- 用库函数priority_queue,快捷创建一个优先列表 pq,pair是它的数据基本元素,vector是他的容器类型,pq则是咱们刚才自定义的比较方式。
6、for (const auto& edge : graph[u]):
- C++的一种读取数据的快捷方式,auto:自动开始读取 graph[u]数组的每个元素,赋值给变量edge,对了,特别注意!!graph是一个二维数组,这里graph[u]则是类似成一个行向量,也就是一维数组,假如有一个数组是arr[100],那么这里直接就可以写成:for (const auto& x : arr),这个x只是一种临时变量,用来读取数据,再有问题,可以直接询问AI,问它的一些简单用法什么的。
三、详细文字举例说明
- 图的设定
- 假设我们有一个简单的图,包含4个顶点,分别编号为0、1、2、3 。图的邻接表存储在
graph中,graph是一个二维vector,其中graph[i]表示从顶点i出发的所有边。例如,graph[0]存储从顶点0出发的边信息。 - 假设从顶点0出发有两条边,一条到顶点1,权重为10;另一条到顶点2,权重为3,那么
graph[0]中会有两个Edge结构体元素:{1, 10}和{2, 3}。
- 假设我们有一个简单的图,包含4个顶点,分别编号为0、1、2、3 。图的邻接表存储在
- 初始化阶段
- 距离数组初始化:
dijkstra函数开始时,n是图中顶点的数量,这里n = 4。dist数组用于存储从源点到各个顶点的最短距离,首先将dist数组的所有元素初始化为numeric_limits<int>::max(),即无穷大,表示尚未找到到这些顶点的有效路径。 - 源点距离设置: 然后将源点
start到自身的距离设为0,即dist[start] = 0。假设源点start = 0,那么dist[0] = 0。 - 优先队列初始化:创建一个优先队列
pq,优先队列中存储的元素是pair<int, int>,第一个int表示顶点,第二个int表示从源点到该顶点的距离。将源点和其距离(0)加入优先队列,即pq.push({start, 0}),此时优先队列pq中有一个元素{0, 0}。
- 距离数组初始化:
- 迭代阶段
- 第一次迭代:
- 从优先队列
pq中取出元素,u = pq.top().first,d = pq.top().second,此时取出的元素是{0, 0},所以u = 0,d = 0,然后将该元素从优先队列中弹出(pq.pop())。 - 遍历顶点
u = 0的所有邻接顶点。graph[0]中有到顶点1和顶点2的边。对于到顶点1的边,v = 1,weight = 10,由于dist[0] + 10 = 0 + 10 = 10 < dist[1](此时dist[1]是无穷大),所以更新dist[1] = 10,并将{1, 10}加入优先队列pq。对于到顶点2的边,v = 2,weight = 3,因为dist[0] + 3 = 0 + 3 = 3 < dist[2](此时dist[2]是无穷大),更新dist[2] = 3,并将{2, 3}加入优先队列pq。此时优先队列pq中有两个元素{2, 3}和{1, 10}。
- 从优先队列
- 第二次迭代:
- 从优先队列
pq中取出元素,由于优先队列是按照距离从小到大排序(由CompareDist定义),取出的元素是{2, 3},所以u = 2,d = 3,然后弹出该元素。 - 遍历顶点
u = 2的所有邻接顶点。假设graph[2]中有到顶点1和顶点3的边(权重假设分别为4和8)。对于到顶点1的边,v = 1,weight = 4,此时dist[2] + 4 = 3 + 4 = 7 < dist[1](dist[1]之前是10),所以更新dist[1] = 7,并将{1, 7}加入优先队列(此时优先队列中{1, 7}会替换掉原来的{1, 10},因为7 < 10)。对于到顶点3的边,v = 3,weight = 8,由于dist[2] + 8 = 3 + 8 = 11 < dist[3](此时dist[3]是无穷大),更新dist[3] = 11,并将{3, 11}加入优先队列。此时优先队列pq中有两个元素{1, 7}和{3, 11}。
- 从优先队列
- 第三次迭代:
- 从优先队列
pq中取出元素,取出的是{1, 7},所以u = 1,d = 7,然后弹出该元素。 - 遍历顶点
u = 1的所有邻接顶点。假设graph[1]中有到顶点3的边(权重假设为2)。对于到顶点3的边,v = 3,weight = 2,此时dist[1] + 2 = 7 + 2 = 9 < dist[3](dist[3]之前是11),所以更新dist[3] = 9,并将{3, 9}加入优先队列(替换掉原来的{3, 11})。此时优先队列pq中只有一个元素{3, 9}。
- 从优先队列
- 第四次迭代:
- 从优先队列
pq中取出元素,取出的是{3, 9},所以u = 3,d = 9,然后弹出该元素。 - 遍历顶点
u = 3的所有邻接顶点。假设没有新的边能使其他顶点的距离更短。此时优先队列pq为空。
- 从优先队列
- 第一次迭代:
- 结束阶段
- 当优先队列
pq为空时,dijkstra算法结束。此时dist数组中存储了从源点(这里是顶点0)到各个顶点的最短距离。例如,dist[0] = 0,dist[1] = 7,dist[2] = 3,dist[3] = 9。这些距离值可以用于后续的分析,比如确定图中不同顶点之间的最短路径长度等。
- 当优先队列

1366

被折叠的 条评论
为什么被折叠?



