【R】Dijkstra算法求最短路径

ops/2025/2/11 8:43:41/

使用R语言实现Dijkstra算法求最短路径

求点2、3、4、5、6、7到点1的最短距离和路径

1.设置data,存放有向图信息

data中每个点所在的行序号为起始点序号,列为终点序号。

比如:值4的坐标为(1,2)即点1到点2距离为4;值8的坐标为(6,7)即点6到点7距离为8;INF表示x->y不通。

代码 

m <- Inf
num <- 7
data <- matrix(c(m, 4, 6, 6, m, m, m,m, m, 1, m, 7, m, m,m, m, m, m, 6, 4, m,m, m, 2, m, m, 5, m,m, m, m, m, m, m, 6,m, m, m, m, 1, m, 8,m, m, m, m, m, m, m
), nrow = num, byrow = TRUE)

2.辅助参数设置 

dist:每个点到初始点的距离,设置为INF,之后根据data中距离进行更新,最后可以得到每个点到初始点的最短距离
path:初始点到每个点的最短路线中,每个点前面的路径;比如点1->点3的最短路径为点1->点2->点3;那么最后path[3]中存的即是节点2
mark:起始值为0,代表还没有进行更新(找到到起始点的最短距离)
后续使用双重for循环,在最初点开始一轮更新后,以每个点为起始点继续更新(以该点为起始更新完后,该点前面的最小距离已经确定,不再参与后续更新,其mark被设置为1),这个过程需要遍历每个点

代码 

dist <- rep(m,num)
path <- rep(-1,num)
mark <- rep(0,num)

此处参考资料:Dijkstra算法求最短路径_哔哩哔哩_bilibili

3.Min():更新过程中分离出来的便捷函数

在全部的节点中寻找mark[i] == 0,即没访问过的点中有最小值的点,返回w,作为下一轮内循环的k,开始更新联通的点

代码 

Min <- function(last){w = 1while (mark[w] != 0){w <- w+1}for (i in 1:last){if (mark[i] == 0 && dist[i] < dist[w]){w = i}}return(w)
}

4.Dijkstra算法主要过程 

4.1.起点初始化

4.1初始点为点1,更新其三个参数

代码 

k = 1
dist[k] = 0
path[k] = -1
mark[k] = 1

4.2.内外循环  

内循环:如果dist[i] > dist[k] + data[k,i]成立,说明k点到i点是通的(不是INF),即根据点k更新点i(和点k联通的多个点)
比如从点1开始(初始k的距离为0:dist[k] = 0)遍历全部点,更新联通的点2,3,4,结束第一次内循环
外循环:第一次内循环结束后,使用函数Min()找和点1联通的点中dist最小的点,标记为mark[k] = 1,结束第一次外循环,第二轮内循环的k为和点1联通的这个最近点
因为基于点k更新的联通点的距离是基于dist[k]的,此时被函数Min()找出,标记为mark[k] = 1,不再参加后续更新
注意k的顺序不是按序号来的,取决于data,比如点2,3,4和1联通,第二次从2开始更新和2联通的3和5,点3就还可以更新,接着从点3开始更新5和6,但是接着从4开始,只取决于距离
接着遍历全部的点,找到目前距离最短的,没有完成更新的点,标记结束后作为下一次更新的起始点

代码 

for(x in 2:num){ # 遍历全部的点for (i in 2:num){ # 以点1开始更新联通点,其实因为有if (mark[i] == 0),所以2:num还是1:num无所谓if (mark[i] == 0){if (dist[i] > dist[k] + data[k,i]){dist[i] = dist[k] + data[k,i]path[i] = k}}}k = Min(num) # 从联通点中距离最短的点开始继续更新该点的联通点 mark[k] = 1 # 比如,点1的联通点中最小点为2,那么下一轮从2开始,同时点2不再更新,点3、4还有更新的机会
}

5.可视化 

代码 

## 打印终点到终点的最短距离----
cat("Shortest distance to node",num,":", dist[num], "\n")## 打印每个节点的最短路径和距离----
for (u in 1:num){cat(sprintf("Shortest Path to node %d: %d -> %d\n", u, path[u], u))cat(sprintf("Minimum Distance to node %d: %d\n", u, dist[u]))
}

完整代码

# 设置data,存放有向图信息----
## data中每个点所在的行序号为起始点序号,列为终点序号----
### 比如:值4的坐标为(1,2)即点1到点2距离为4;值8的坐标为(6,7)即点6到点7距离为8;INF表示x->y不通----
m <- Inf
num <- 7
data <- matrix(c(m, 4, 6, 6, m, m, m,m, m, 1, m, 7, m, m,m, m, m, m, 6, 4, m,m, m, 2, m, m, 5, m,m, m, m, m, m, m, 6,m, m, m, m, 1, m, 8,m, m, m, m, m, m, m
), nrow = num, byrow = TRUE)# 辅助参数----
## dist:每个点到初始点的距离,设置为INF,之后根据data中距离进行更新,最后可以得到每个点到初始点的最短距离----
## path:初始点到每个点的最短路线中,每个点前面的路径;比如点1->点3的最短路径为点1->点2->点3;那么最后path[3]中存的即是节点2----
## mark:起始值为0,代表还没有进行更新(找到到起始点的最短距离)----
## 后续使用双重for循环,在最初点开始一轮更新后,以每个点为起始点继续更新(以该点为起始更新完后,该点前面的最小距离已经确定,不再参与后续更新,其mark被设置为1),这个过程需要遍历每个点----
dist <- rep(m,num)
path <- rep(-1,num)
mark <- rep(0,num)
### 此处参考资料:https://www.bilibili.com/video/BV11P4y1a7X9/?spm_id_from=333.999.0.0&vd_source=709bfcb2343a93fce7f20d52e9a6c8cf# 更新过程中分离出来的便捷函数----
## 在全部的节点中寻找mark[i] == 0,即没访问过的点中有最小值的点,返回w,作为下一轮内循环的k,开始更新联通的点----
Min <- function(last){w = 1while (mark[w] != 0){w <- w+1}for (i in 1:last){if (mark[i] == 0 && dist[i] < dist[w]){w = i}}return(w)
}# Dijkstra算法主要过程----
## 初始点为点1,更新其三个参数
k = 1
dist[k] = 0
path[k] = -1
mark[k] = 1
## 内循环:如果dist[i] > dist[k] + data[k,i]成立,说明k点到i点是通的(不是INF),即根据点k更新点i(和点k联通的多个点)
### 比如从点1开始(初始k的距离为0:dist[k] = 0)遍历全部点,更新联通的点2,3,4,结束第一次内循环
## 外循环:第一次内循环结束后,使用函数Min()找和点1联通的点中dist最小的点,标记为mark[k] = 1,结束第一次外循环,第二轮内循环的k为和点1联通的这个最近点
### 因为基于点k更新的联通点的距离是基于dist[k]的,此时被函数Min()找出,标记为mark[k] = 1,不再参加后续更新
### 注意k的顺序不是按序号来的,取决于data,比如点2,3,4和1联通,第二次从2开始更新和2联通的3和5,点3就还可以更新,接着从点3开始更新5和6,但是接着从4开始,只取决于距离
### 接着遍历全部的点,找到目前距离最短的,没有完成更新的点,标记结束后作为下一次更新的起始点
for(x in 2:num){ # 遍历全部的点for (i in 2:num){ # 以点1开始更新联通点,其实因为有if (mark[i] == 0),所以2:num还是1:num无所谓if (mark[i] == 0){if (dist[i] > dist[k] + data[k,i]){dist[i] = dist[k] + data[k,i]path[i] = k}}}k = Min(num) # 从联通点中距离最短的点开始继续更新该点的联通点 mark[k] = 1 # 比如,点1的联通点中最小点为2,那么下一轮从2开始,同时点2不再更新,点3、4还有更新的机会
}# 可视化----
## 打印终点到终点的最短距离----
cat("Shortest distance to node",num,":", dist[num], "\n")## 打印每个节点的最短路径和距离----
for (u in 1:num){cat(sprintf("Shortest Path to node %d: %d -> %d\n", u, path[u], u))cat(sprintf("Minimum Distance to node %d: %d\n", u, dist[u]))
}

http://www.ppmy.cn/ops/157481.html

相关文章

【万字详细教程】Linux to go——装在移动硬盘里的Linux系统(Ubuntu22.04)制作流程;一口气解决系统安装引导文件迁移显卡驱动安装等问题

Linux to go制作流程 0.写在前面 关于教程Why Linux to go&#xff1f;实际效果 1.准备工具2.制作步骤 下载系统镜像硬盘分区准备启动U盘安装系统重启完成驱动安装将系统启动引导程序迁移到移动硬盘上 3.可能出现的问题 3.1.U盘引导系统安装时出现崩溃3.2.不影响硬盘里本身已有…

桥接模式——C++实现

目录 1 桥接模式定义 2 桥接模式小例子 3 桥接模式的总结 1 桥接模式定义 首先来看看桥接模式的官方定义吧&#xff1a; 桥接模式是将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。它是一种结构型模式。 桥接模式的定义确实比较难理解&#xff0c;比较抽…

网络安全架构分层 网络安全组织架构

1.1.4 网络安全系统的基本组成 上节介绍到了&#xff0c;网络安全系统是一个相对完整的安全保障体系。那么这些安全保障措施具体包括哪些&#xff0c;又如何体现呢&#xff1f;这可以从OSI/RM的7层网络结构来一一分析。因为计算机的网络通信&#xff0c;都离不开OSIR/RM的这7层…

【图片合并转换PDF】如何将每个文件夹下的图片转化成PDF并合并成一个文件?下面基于C++的方式教你实现

医院在为患者进行诊断和治疗过程中&#xff0c;会产生大量的医学影像图片&#xff0c;如 X 光片、CT 扫描图、MRI 图像等。这些图片通常会按照检查时间或者检查项目存放在不同的文件夹中。为了方便医生查阅和患者病历的长期保存&#xff0c;需要将每个患者文件夹下的图片合并成…

【系统架构设计师】嵌入式系统之JTAG接口

目录 1. 说明2. 主要功能2.1 硬件调试2.2 边界扫描测试2.3 系统内编程&#xff08;ISP&#xff09;2.4 配置和重新配置2.5 实时监控 3. 核心组件和引脚4. 应用场景5. 使用注意事项6. 例题6.1 例题1 1. 说明 1.嵌入式系统中的JTAG&#xff08;Joint Test Action Group&#xff…

PLSQL: 存储过程,用户自定义函数[oracle]

注意: raise notice是高斯的输出语句; DBMS_OUT_PUT.PUT_LINE是oracle的输出语句 存储过程 Stored Procedure 存储过程可以封装数据访问逻辑&#xff0c;使得应用程序可以通过调用存储过程来执行这些逻辑&#xff0c;而不是直接执行SQL语句。这有助于提高代码的可重用性、可…

深入浅出:机器学习的全面解析

深入浅出&#xff1a;机器学习的全面解析 引言 机器学习&#xff08;Machine Learning, ML&#xff09;作为人工智能的一个重要分支&#xff0c;近年来取得了显著进展&#xff0c;并在多个领域中得到了广泛应用。本文将从基础概念、核心算法、应用场景以及未来发展趋势等方面…

跨越边界,大模型如何助推科技与社会的完美结合?

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 概述 2024年&#xff0c;大模型技术已成为人工智能领域的焦点。这不仅仅是一项技术进步&#xff0c;更是一次可能深刻影响社会发展方方面面的变革。大模型的交叉能否推动技术与社会的真正融合&#xff1f;2025年…