迪杰斯特拉算法详解

news2024/9/25 15:27:39

迪杰斯特拉算法详解

首先要知道的是,迪杰斯特拉算法是求解单源最短路径的,就是在一个图中(无向图和有向图均可),指定一个源点,求出来这个源点到其他各个节点的最短路径。
在这里插入图片描述

存图

首先,我需要用邻接矩阵把图存起来,邻接矩阵也就是一个二维数组。例如如果节点1到节点2的距离为20,那么邻接矩阵的 [1] [2] = 20。 我是这样保存的:如果题目中没提到距离,只是说明了是否存在路径,那么就将存在路径的邻接矩阵值设置为1,否则设置为0,设置 [i] [i] = 1,因为自身肯定是能到达自身的嘛;如果题目给了节点之间的距离,那么对应的邻接矩阵的值也要设置为其距离,到不了的就设置为INF(无穷大),设置 [i] [i] = 0,因为自身到自身的距离肯定是0。
以没提到距离的情况来写代码就是这样的:

class Graph  : public QObject
{
	Q_OBJECT

public:
	Graph(int V, QObject *parent);
	~Graph();

	void addEdge(int u, int v, int w);
private:
	int V;  // 顶点的数量
	int adjMatrix[MAX][MAX];  // 邻接矩阵
};

在构造函数中初始化邻接矩阵

Graph::Graph(int V, QObject *parent)
	: V(V),
	QObject(parent)
{
	for (int i = 0; i < V; ++i)
        for (int j = 0; j < V; ++j)
        {
            // 初始化邻接矩阵
            adjMatrix[i][j] = (i == j) ? 1 : INF;
            // 如果是有距离的情况,写这个
            // adjMatrix[i][j] = (i == j) ? 0 : INF;
        }
			
}

添加边

void Graph::addEdge(int u, int v, int w)
{
	adjMatrix[u][v] = w;
	adjMatrix[v][u] = w;
}

迪杰斯特拉思路

首先,我需要设置一个容器,假设为A,A中存放的是当前已经访问过的节点以及该节点到达源点的最短距离(注意,这个会随着后面节点的加入而不断更新)。同时,还需要设置一个数组visited来标记这个节点是否已经访问过(不然我怎么知道这个节点有没有被访问过呢),再设置一个数组parent用来保存计算好的最短路径,例如 parent [5] = 1 ,表示节点5的父节点为节点1,依次再找出节点1的父节点……就能够找到最短路径。

然后就是,先把我的源点放入容器A中,同时设置状态为已访问,目前起点就是我的源点,然后从剩下的未被访问过的节点中依次取出与起点相连通的节点进行比较,如果节点到起点的距离与起点到源点的距离之和小于源点到该节点的距离,那么就将此节点和其到源点的距离放入A中,同时设置其parent值为起点。

然后从A中取出到源点距离最近的节点,将起点改为此节点,同时设置状态为已访问,然后再次从剩下的未被访问过的节点中依次取出与起点相连通的节点进行比较,如果节点到起点的距离与起点到源点的距离之和小于源点到该节点的距离,那么就将此节点和其到源点的距离放入A中,同时设置其parent值为起点(如果A中已经存在此节点,那么就更新其距离为它到当前设置的起点的距离与起点到源点的距离之和,同时更新parent值为当前设置的起点)。

以此类推,直到所有节点均被访问为止。这里使用到的原理是,如果某个节点到起点的距离是最短的,那么它到源点的距离也将是最短的,通过遍历不同的起点,不断比较和更新节点到源点的距离,来得到最优解。

只看文字有点绕口,来看代码吧!

代码详解

// src就是源点,dist就是上面提到的容器A,adjMatrix就是保存图的邻接矩阵
void Graph::dijkstra(int src, std::vector<int>& dist, int adjMatrix[MAX][MAX])
{
    // 使用优先队列来选择下一个要处理的节点
    // pair<int, int>表示距离和节点的组合,greater确保队列按距离递增的顺序排列(小的在队头)
    // 默认先比较第一个元素,第一个相等则比较第二个
    std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>>> pq;
    // 用于标记节点是否已经被访问
    std::vector<bool> visited(V, false);
    // 初始化存储最短路径的向量为无穷大(INF)
    dist = std::vector<int>(V, INF);
    // 将源节点及其距离(0)放入优先队列
    pq.push(std::make_pair(0, src));
    // 将源节点到自身的距离设置为0
    dist[src] = 0;
    // 用于存储最短路径的父节点
    std::vector<int> parent(V, -1);
    // 进入主循环,直到优先队列为空
    while (!pq.empty()) 
    {
        // 从优先队列中取出当前距离最小的节点
        int u = pq.top().second;
        // 将该节点从优先队列中移除
        pq.pop();
        // 标记当前节点为已访问
        visited[u] = true;
        // 遍历与当前节点相邻的所有节点
        for (int v = 0; v < V; ++v)
        {
            // 检查如果节点未被访问、存在连接边,并且通过当前节点的路径距离更短
            // 这里存在连接边的设置考虑到了路径包含距离与不包含距离的两种情况
            // 包含距离,不存在连接边则adjMatrix[u][v]==INF
            // 不包含距离,不存在连接边则adjMatrix[u][v]==0
            if (!visited[v] && adjMatrix[u][v]!=INF && adjMatrix[u][v] && dist[u] + adjMatrix[u][v] < dist[v])
            {
                // 更新从源节点到节点v的最短路径
                dist[v] = dist[u] + adjMatrix[u][v];
                // 记录最短路径的父节点
                parent[v] = u;
                // 将更新后的节点v及其新距离放入优先队列
                pq.push(std::make_pair(dist[v], v));
            }
        }
    }
}

这里用到了STL里面的优先队列,以此来找到dist中到源点距离最近的节点。
将这个节点作为起点,不断的从剩下未被访问的节点中取出节点,计算出取出的节点到起点的距离与起点到源点的距离之和来与取出的节点到源点的距离作比较,如果前者更小,那么就更新这个节点到源点的距离。

最后当所有节点的状态都是已访问时,直到队列弹出最后一个元素,退出循环。

打印路径

上面说到,路径信息都保存在了parent数组中,该怎么打印出来呢?
简单点,设置一个栈,栈的特性是先进后出,我们把最后一个节点的parent先压入栈中,然后再把最后一个节点的parent的parent压入栈中……最后在压入源点,再依次弹出栈顶元素就好啦!

// src表示源点,dest表示终点
// 如果想得到源点到所有终点的路径,加个循环即可
void Graph::saveDjPath(int src, int dest, std::vector<int>& parent)
{
    std::stack<int> path;
    int current = dest;
    while (current != src) 
    {
    	// 进栈
        path.push(current);
        current = parent[current];
    }
    // 将源点压入栈中
    path.push(src);
    std::cout<<src<<"到"<<dest<<"路径为:";
    while (!path.empty()) 
    {
        std::cout<<path.top()<<' ';
        path.pop();
    }
    cout<<endl;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1334657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS应用兼容稳定性云测试

兼容性测试 兼容性测试主要验证HarmonyOS应用在华为真机设备上运行的兼容性问题&#xff0c;包括首次安装、再次安装、启动、卸载、崩溃、黑白屏、闪退、运行错误、无法回退、无响应、设计约束场景。具体兼容性测试项的详细说明请参考兼容性测试标准。 兼容性测试支持TV、智能穿…

爬虫系列----Python解析Json网页并保存到本地csv

Python解析JSON 1 知识小课堂1.1 爬虫1.2 JSON1.3 Python1.4 前言技术1.4.1 range1.4.2 random1.4.3 time.sleep1.4.4 with open() as f: 2 解析过程2.1 简介2.2 打开调试工具2.3 分析网址2.3.1 网址的规律2.3.2 网址的参数 2.4 爬取第一页内容2.5 存入字典并获取2.6 循环主体数…

DolphinScheduler 介绍及系统架构

目录 一、DolphinScheduler 介绍 1.1 关于 DolphinScheduler 1.2 特性 简单易用 丰富的使用场景 High Reliability High Scalability 1.3 名词解释 1.3.1 名词解释 1.3.2 模块介绍 二、DolphinScheduler 系统架构 2.1 系统架构图 2.2 架构说明 MasterServer 该服…

【Java核心基础】一文带你了解Java中super关键字的重要作用

“super”关键字在编程中扮演着重要角色&#xff0c;它允许我们直接访问父类中的属性、方法或构造函数&#xff0c;即使子类中存在同名元素。此外&#xff0c;“super()”在子类构造函数中调用父类初始化操作&#xff0c;确保父类属性正确初始化。有时&#xff0c;“super”还可…

Python 爬虫之下载视频(五)

爬取第三方网站视频 文章目录 爬取第三方网站视频前言一、基本情况二、基本思路三、代码编写四、注意事项&#xff08;ffmpeg&#xff09;总结 前言 国内主流的视频平台有点难。。。就暂且记录一些三方视频平台的爬取吧。比如下面这个&#xff1a; 一、基本情况 这次爬取的方…

OpenHarmony之内核层解析~

OpenHarmony简介 技术架构 OpenHarmony整体遵从分层设计&#xff0c;从下向上依次为&#xff1a;内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级展开&#xff0c;在多设备部署场景下&#xff0c;支持根据实际需求裁剪某些非必要的组件…

【RocketMQ】Console页面报错:rocketmq remote exception,connect to xxx failed.

现象 console报错&#xff0c;无法连接该节点&#xff0c;把该节点杀掉&#xff0c;还是继续报错&#xff0c;重启之后&#xff0c;报错的端口变成11911。 分析 正常一个broker会启动三个端口&#xff0c;不同版本的规律不太一样&#xff0c;4.X版本是&#xff1a; 配置文件…

如何使用ScrapySharp下载网页内容

C#简介 C#是一种由微软开发的通用、面向对象的编程语言。它结合了C和C的优点&#xff0c;并封装了Java的一些特性。C#被广泛评价Windows平台的软件开发&#xff0c;包括Web应用、桌面应用和游戏开发等领域。 使用场景 在网络数据挖掘和信息收集的过程中&#xff0c;我们需要…

3D模型如何制作透明玻璃材质

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 1、什么是玻璃材质 在3D建模和渲染中&#xff0c;玻璃是一种非常常见…

【期末复习】微信小程序复习大纲( 1- 5 章)

前言&#xff1a; 这周开始进入期末复习周&#xff0c;没时间看C/C、linux等知识了&#xff0c;先把期末考试必考的知识捋一遍。 目录 第一章 微信小程序入门 一、填空题 二、判断题 三、选择题 四、简答题 第二章 微信小程序页面制作 一、填空题 二、判…

【六大排序详解】中篇 :选择排序 与 堆排序

选择排序 与 堆排序 选择排序 选择排序 与 堆排序1 选择排序1.1 选择排序原理1.2 排序步骤1.3 代码实现 2 堆排序2.1 堆排序原理2.1.1 大堆与小堆2.1.2 向上调整算法2.1.3 向下调整算法 2.2 排序步骤2.3 代码实现 3 时间复杂度分析 Thanks♪(&#xff65;ω&#xff65;)&#…

智慧交通应用钡铼技术无线工业边缘路由网关R10A

智慧交通应用中&#xff0c;无线工业边缘路由网关扮演着至关重要的角色。在这方面&#xff0c;钡铼技术无线工业边缘路由网关R10A被广泛应用于交通管理系统中&#xff0c;它具备一路RS485、一路WAN、一路LAN、4G和WiFi等功能。本文将详细介绍R10A的参数以及在智慧交通领域的应用…

蓝桥题库(X图形(矩阵))

题目剖析&#xff1a; 简单来说就是找到一个由字母组成的X图形&#xff0c;且每个边上的字母都与中心点的字母相同 算法设计&#xff1a; 1.从中心点向外辐射&#xff0c;每找到一个这样的图形&#xff0c;则次数加一 2.从最外层向中心点靠拢&#xff0c;如果中间遇到不满足…

Unity Shader Early-Z技术

Unity Shader Early-Z技术 Early-Z技术Unity渲染顺序总结Alpha Test&#xff08;Discard&#xff09;在移动平台消耗较大的原因 Early-Z技术 传统的渲染管线中&#xff0c;ZTest其实是在Blending阶段&#xff0c;这时候进行深度测试&#xff0c;所有对象的像素着色器都会计算一…

外汇天眼:交易高手!是这样炼成的!

在外汇市场中&#xff0c;那些总是赚的“盆满钵满”的外汇投资高手实在是让人羡慕不已&#xff0c;他们能够准确预测市场走势&#xff0c;抓住每一个交易机会&#xff0c;实现高收益&#xff0c;很多投资新手因此也想入市&#xff0c;但即使是这样&#xff0c;还是有很多新手对…

关于标准那些事——第五篇 两仪

国家标准的编写&#xff0c;对于标准的名称和结构&#xff0c;很多人往往是不那么在意的&#xff0c;但这恰恰也是非常重要的点&#xff0c;今天就给大家分享一下这太极所生的“两仪”。我会用最精简的文字概括出核心内容&#xff0c;让大家有一个初步且完整的概念&#xff0c;…

规律生活指南:数据可视化助你游刃有余

随着信息时代的到来&#xff0c;我们生活在一个数据海洋中&#xff0c;每天都会面对大量的信息和数字。在这个信息过载的时代&#xff0c;如何从杂乱的数据中找到规律&#xff0c;让生活更加有序成为了一项挑战。而数据可视化作为一种强大的工具&#xff0c;不仅能够帮助我们理…

算法基础之数字三角形

数字三角形 核心思想&#xff1a;线性dp 集合的定义为 f[i][j] –> 到i j点的最大距离 从下往上传值 父节点f[i][j] max(f[i1][j] , f[i1][j1]) w[i][j] 初始化最后一层 f w #include <bits/stdc.h>using namespace std;const int N 510;int w[N][N],f[N][…

ACM模式Java输入输出模板

输入输出练习网站&#xff1a;https://kamacoder.com/ Java读写模板 Scanner 方式一&#xff1a;Scanner&#xff08;效率不高&#xff09; public class Main {public static void main(String[] args) {// 第一个方式ScannerScanner sc new Scanner(System.in);String s …

SpringMVC核心处理流程梳理

1、处理流程图展示 当我拿出这张图&#xff0c;阁下又该如何应对呢&#xff1f;执行流程是不是一目了然了。 2、DispatcherServlet&#xff1a;中央处理器或者中央调度器 下图官方的解释应该最完善了。 3、SpringMVC三大核心组件 HandlerMapping 处理器映射器&#xff0c;…