Dijkstra算法简要-个人理解

一、代码实例

先欣赏一下优美的算法代码

#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}
  1. 初始化阶段
    • 距离数组初始化dijkstra 函数开始时,n 是图中顶点的数量,这里 n = 4dist 数组用于存储从源点到各个顶点的最短距离,首先将 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}
  2. 迭代阶段
    • 第一次迭代
      • 从优先队列 pq 中取出元素,u = pq.top().firstd = pq.top().second,此时取出的元素是 {0, 0},所以 u = 0d = 0,然后将该元素从优先队列中弹出(pq.pop())。
      • 遍历顶点 u = 0 的所有邻接顶点。graph[0] 中有到顶点1和顶点2的边。对于到顶点1的边,v = 1weight = 10,由于 dist[0] + 10 = 0 + 10 = 10 < dist[1](此时 dist[1] 是无穷大),所以更新 dist[1] = 10,并将 {1, 10} 加入优先队列 pq。对于到顶点2的边,v = 2weight = 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 = 2d = 3,然后弹出该元素。
      • 遍历顶点 u = 2 的所有邻接顶点。假设 graph[2] 中有到顶点1和顶点3的边(权重假设分别为4和8)。对于到顶点1的边,v = 1weight = 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 = 3weight = 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 = 1d = 7,然后弹出该元素。
      • 遍历顶点 u = 1 的所有邻接顶点。假设 graph[1] 中有到顶点3的边(权重假设为2)。对于到顶点3的边,v = 3weight = 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 = 3d = 9,然后弹出该元素。
      • 遍历顶点 u = 3 的所有邻接顶点。假设没有新的边能使其他顶点的距离更短。此时优先队列 pq 为空。
  3. 结束阶段
    • 当优先队列 pq 为空时,dijkstra 算法结束。此时 dist 数组中存储了从源点(这里是顶点0)到各个顶点的最短距离。例如,dist[0] = 0dist[1] = 7dist[2] = 3dist[3] = 9 。这些距离值可以用于后续的分析,比如确定图中不同顶点之间的最短路径长度等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值