【图论】迪杰斯特拉算法详解

一、引言

迪杰斯特拉算法(Dijkstra’s Algorithm)是解决单源最短路径问题的一种经典算法,广泛应用于网络路由、地图导航等领域。它的核心思想是通过贪心策略,不断扩展到当前已知的最短路径,最终找到从起点到各个节点的最短路径。

二、基本概念

  • 图的定义:图由节点(顶点)和边组成,可以表示为 ( G(V, E) ),其中 ( V ) 为节点集合,( E ) 为边集合。
  • 权重:边的权重通常表示从一个节点到另一个节点的距离或费用。
  • 单源最短路径:给定一个源节点,找到到所有其他节点的最短路径。

三、算法原理

迪杰斯特拉算法的基本步骤如下:

  1. 初始化

    • 设置源节点到自身的距离为 0,到其他所有节点的距离为无穷大。
    • 将所有节点标记为未访问。
  2. 选择最小距离节点

    • 从未访问的节点中选择一个距离源节点最近的节点,记为当前节点。
  3. 更新邻接节点的距离

    • 对于当前节点的每一个邻接节点,计算从源节点到该邻接节点的距离,如果该距离小于已知的距离,则更新。
  4. 标记当前节点为已访问

    • 将当前节点标记为已访问。
  5. 重复步骤 2-4

    • 直到所有节点都被访问。

四、算法步骤

  1. 创建一个图:使用邻接表或邻接矩阵表示。
  2. 实现迪杰斯特拉算法:通过优先队列优化选择最小距离节点的过程。

五、时间复杂度

  • 使用邻接矩阵实现:O(V^2),其中 V 为节点数量。
  • 使用优先队列(如堆)实现:O((V + E) * log V),其中 E 为边的数量。

六、代码实现

以下是迪杰斯特拉算法的 C++ 代码实现:

#include <iostream>
#include <vector>
#include <queue>
#include <limits>
#include <utility>

using namespace std;

const int INF = numeric_limits<int>::max(); // 定义无穷大

// 图的结构
class Graph {
public:
    int V; // 节点数
    vector<vector<pair<int, int>>> adj; // 邻接表,pair<邻接节点, 权重>

    Graph(int V) {
        this->V = V;
        adj.resize(V);
    }

    void addEdge(int u, int v, int weight) {
        adj[u].push_back(make_pair(v, weight)); // 添加边
        adj[v].push_back(make_pair(u, weight)); // 无向图,添加反向边
    }

    void dijkstra(int start) {
        vector<int> distance(V, INF); // 初始化距离为无穷大
        vector<bool> visited(V, false); // 标记节点是否已访问
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; // 小根堆

        distance[start] = 0; // 源节点到自身的距离为0
        pq.push(make_pair(0, start)); // 将源节点入队

        while (!pq.empty()) {
            int u = pq.top().second; // 当前节点
            pq.pop();

            if (visited[u]) continue; // 已访问,跳过

            visited[u] = true; // 标记为已访问

            // 遍历邻接节点
            for (auto& edge : adj[u]) {
                int v = edge.first; // 邻接节点
                int weight = edge.second; // 边的权重

                // 如果通过当前节点到达邻接节点的距离更短,则更新
                if (distance[u] + weight < distance[v]) {
                    distance[v] = distance[u] + weight;
                    pq.push(make_pair(distance[v], v)); // 将邻接节点入队
                }
            }
        }

        // 输出结果
        for (int i = 0; i < V; ++i) {
            cout << "从节点 " << start << " 到节点 " << i << " 的最短距离为 " << distance[i] << endl;
        }
    }
};

int main() {
    // 创建图
    Graph g(5);
    g.addEdge(0, 1, 10);
    g.addEdge(0, 4, 5);
    g.addEdge(1, 2, 1);
    g.addEdge(1, 4, 2);
    g.addEdge(2, 3, 4);
    g.addEdge(3, 0, 7);
    g.addEdge(4, 1, 3);
    g.addEdge(4, 2, 9);
    g.addEdge(4, 3, 2);

    g.dijkstra(0); // 从节点0开始计算最短路径

    return 0;
}

七、代码解析

  1. 图的构建

    • 使用邻接表存储图,adj 为图的边和权重。
    • addEdge 方法用于添加边。
  2. Dijkstra 方法

    • 使用优先队列来高效选择未访问节点中最短的。
    • 更新每个邻接节点的最短距离,如果通过当前节点到达邻接节点的距离更短,则更新。
  3. 结果输出

    • 最后输出从源节点到每个节点的最短距离。

八、应用场景

  1. 地图导航:在交通系统中,用于计算两地之间的最短行驶路线。
  2. 网络路由:在计算机网络中,选择数据包传输的最优路径。
  3. 游戏开发:用于 NPC(非玩家角色)在地图上的移动路径计算。

九、总结

迪杰斯特拉算法是一种有效解决单源最短路径问题的算法。通过优先队列的应用,它的时间复杂度得到了显著的优化。理解并掌握该算法的实现,对于学习图论和解决实际问题都是非常重要的。希望本篇文章能够帮助你更好地理解和应用迪杰斯特拉算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只蜗牛儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值