Dijistra算法以及flody算法详解及代码注释

迪杰斯特拉算法

一、算法简介

迪杰斯特拉算法(Dijkstra’s Algorithm)是由荷兰计算机科学家艾茲赫爾·迪克斯特拉(Edsger W. Dijkstra)在1956年提出的一种用于求解图中单源最短路径问题的算法。它适用于带权有向图和无向图,要求图中没有负权重的边。算法的核心思想是通过贪心策略,每次选择距离起点最近的节点进行扩展,逐步找到从起点到所有其他节点的最短路径。

二、算法优势

  1. 效率高:对于稀疏图,使用二叉堆或斐波那契堆实现的迪杰斯特拉算法具有较高的效率。
  2. 适用范围广:适用于各种带权图,包括有向图和无向图,只要权重为非负
  3. 简单易懂:算法思路清晰,易于理解和实现。

三、算法核心

迪杰斯特拉算法的核心是维护一个优先队列(通常使用最小堆实现),用于存储当前已知最短路径的节点。在算法运行过程中,不断从队列中取出距离起点最近的节点,对其邻接节点进行松弛操作,更新这些节点的最短路径。具体步骤如下:

  1. 初始化:将起点到起点的距离设置为0,其他所有节点的距离设置为∞,将所有节点放入最小堆中。
  2. 取堆顶节点:从最小堆中取出距离起点最近的节点,记为当前节点。
  3. 更新邻接节点:对当前节点的每个邻接节点,检查从起点通过当前节点到该邻接节点的距离是否比当前已知的最短距离更短。如果是,则更新该邻接节点的距离,并将其重新插入最小堆。
  4. 重复步骤2和3,直到最小堆为空或所有节点都已被访问。

四、算法C++实现

以下是迪杰斯特拉算法的C++实现,使用优先队列来实现最小堆:

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

using namespace std;
using pii = pair<int, int>;

// 迪杰斯特拉算法实现
vector<int> dijkstra(const vector<vector<pii>>& graph, int start) {
    int n = graph.size();
    vector<int> dist(n, INT_MAX);
    vector<bool> visited(n, false);
    dist[start] = 0;

    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push({ 0, start });

    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();

        if (visited[u]) continue;
        visited[u] = true;

        for (const auto& edge : graph[u]) {
            int v = edge.first;
            int weight = edge.second;

            if (dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
                pq.push({ dist[v], v });
            }
        }
    }

    return dist;
}

int main() {
    int n = 5; // 图的节点数
    vector<vector<pii>> graph(n);

    // 添加边 (节点1, 节点2, 权重)
    graph[0].push_back({ 1, 10 });
    graph[0].push_back({ 3, 5 });
    graph[1].push_back({ 2, 1 });
    graph[1].push_back({ 3, 2 });
    graph[2].push_back({ 4, 4 });
    graph[3].push_back({ 1, 3 });
    graph[3].push_back({ 2, 9 });
    graph[3].push_back({ 4, 2 });
    graph[4].push_back({ 2, 6 });

    int start = 0; // 起点
    vector<int> distances = dijkstra(graph, start);

    for (int i = 0; i < distances.size(); ++i) {
        cout << "从节点" << start << " 到节点 " << i << " 的最短路径是 " << distances[i] << endl;
    }

    return 0;
}

请添加图片描述

五、代码解释

  1. 数据结构定义:使用vector<vector<pii>>来表示图,其中pii是一个pair<int, int>,第一个元素表示邻接节点,第二个元素表示边的权重。
  2. 初始化dist数组用于存储从起点到各个节点的最短距离,初始时设置为INT_MAX(表示无穷大),起点距离自身为0。使用优先队列pq来存储当前已知最短路径的节点。
  3. 主循环:从优先队列中取出距离起点最近的节点,对其每个邻接节点进行松弛操作,如果通过当前节点到达邻接节点的距离更短,则更新该邻接节点的最短距离,并将其重新插入优先队列。
  4. 输出结果:最后输出从起点到各个节点的最短距离。

六、数据分析

下图为最初的图及其权重

在这里插入图片描述

最初的情况是:

1、堆中只有一个数据对 {0,start},表示从startstart的距离最短为0。从这一步开始迭代。

1.1、如果start节点被访问过,那么就回到循环,很显然,start没有被访问过

1.2、遍历可以从start到达的节点,如果从start开始加上权重低于dist中记录过得最小值, 那么更新dist,并且将这一堆添加到堆中。

看一下数据结果

堆的值:{0,0}
dist数组的值 {0,2147483647,2147483647,2147483647,2147483647}
堆的值:{5,3}
dist数组的值 {0,10,2147483647,5,2147483647}
堆的值:{7,4}
dist数组的值 {0,8,14,5,7}
堆的值:{8,1}
dist数组的值 {0,8,13,5,7}
堆的值:{9,2}
dist数组的值 {0,8,9,5,7}
堆的值:{10,1}
dist数组的值 {0,8,9,5,7}
堆的值:{13,2}
dist数组的值 {0,8,9,5,7}
堆的值:{14,2}
dist数组的值 {0,8,9,5,7}

Floyd-Warshall算法

Floyd-Warshall算法是一种用于计算加权图中所有节点间最短路径的算法。它以动态规划的思想,通过逐步增加考虑中间节点,更新所有节点对之间的最短路径。这一算法不仅可以处理有向图,也可以处理无向图,且能处理负权重的边,只要图中不存在负权重的环。

一、算法优势

  1. 简单直观:算法思路简单,容易理解和实现。
  2. 全局最优:能够计算出图中所有节点对之间的最短路径,提供全局最优解。
  3. 适用于负权重:可以处理带有负权重的边,只要没有负权重环。

二、算法核心

Floyd-Warshall算法的核心思想是通过增加中间节点,逐步更新最短路径。具体步骤如下:

  1. 初始化:创建一个二维数组dist,其中dist[i][j]表示节点i到节点j的最短距离。初始时,dist[i][j]设置为边(i, j)的权重,如果没有直接的边,则设置为无穷大。
  2. 动态规划:对每个节点k,检查通过节点k是否能使节点i到节点j的距离变得更短。如果是,则更新dist[i][j]
  3. 重复步骤2,直到所有节点都被考虑为中间节点。

三、算法C++实现

以下是Floyd-Warshall算法的C++实现:

#include <iostream>
#include <vector>
#include <climits>

using namespace std;

// Floyd-Warshall算法实现
void floydWarshall(vector<vector<int>>& graph) {
    int n = graph.size();
    vector<vector<int>> dist = graph;

    for (int k = 0; k < n; ++k) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX && dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }

    // 输出结果
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (dist[i][j] == INT_MAX) {
                cout << "INF ";
            } else {
                cout << dist[i][j] << " ";
            }
        }
        cout << endl;
    }
}

int main() {
    int n = 4; // 图的节点数
    vector<vector<int>> graph = {
        {0, 3, INT_MAX, 7},
        {8, 0, 2, INT_MAX},
        {5, INT_MAX, 0, 1},
        {2, INT_MAX, INT_MAX, 0}
    };

    floydWarshall(graph);

    return 0;
}

请添加图片描述

四、代码解释

  1. 初始化dist数组用于存储节点间的最短距离,初始时设置为graph的权重矩阵。
  2. 动态规划:三重循环遍历每个节点k,检查通过节点k是否能使节点i到节点j的距离变得更短。如果是,则更新dist[i][j]
  3. 输出结果:最后输出所有节点对之间的最短距离。如果两个节点间没有路径,则输出INF表示无穷大。

五、结论

Floyd-Warshall算法是一种强大的算法,能够计算图中所有节点对之间的最短路径。它的实现简单,适用于处理负权重的边,但其时间复杂度为O(n^3),因此在处理大规模图时效率较低。

算法的不同

Dijistra是计算一个点到所有点的最短路径,Flody是计算所有点到所有点的最短路径。

Dijistra权值中不能存在负数,Flody中权值可以存在负数。

  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
安装SQL Server的步骤如下: 1. 首先,你需要下载并安装SQL Server。安装程序可以从Microsoft官方网站下载。确保选择与你操作系统兼容的版本。 2. 打开安装程序并按照提示进行安装。在安装过程中,你可以选择不同的组件来满足你的需求。例如,你可以选择安装数据库引擎、分析服务、集成服务等。 3. 在安装过程中,你可能需要指定一些设置,如安装路径、实例名称、身份验证模式等。根据你的需求和环境选择适当的选项。 4. 安装完成后,你需要安装SQL Server Management Studio (SSMS) 来管理和操作SQL Server数据库。SSMS是一个独立的工具,需要单独下载和安装。 5. 你可以从Microsoft官方网站下载SSMS安装程序。确保选择与你所安装的SQL Server版本兼容的SSMS版本。 6. 打开SSMS安装程序并按照提示进行安装。在安装过程中,你可以选择安装位置和其他配置选项。 7. 安装完成后,你可以启动SSMS,并使用连接信息来连接到你的SQL Server实例。连接信息包括服务器名称、身份验证方式、用户名和密码等。 8. 一旦成功连接到SQL Server,你就可以使用SSMS来管理数据库、执行查询、创建表格和视图等操作。 请注意,安装步骤可能会因你使用的SQL Server版本而有所不同。所以在安装之前,最好查阅相关文档以获取最新的安装说明和指南。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [SQL Server 安装图解](https://blog.csdn.net/diji2672/article/details/101287916)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LyaJpunov

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

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

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

打赏作者

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

抵扣说明:

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

余额充值