【R】Dijkstra算法求最短路径

news/2025/2/8 11:28:29 标签: r语言, 算法, 贪心算法

使用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 = 1
  while (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 = 1
  while (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.niftyadmin.cn/n/5844805.html

相关文章

Day56_20250204_图论part1_图论理论基础|深搜理论基础|98.所有可达路径|广搜理论基础

Day56_20250204_图论part1_图论理论基础|深搜理论基础|98.所有可达路径|广搜理论基础 深搜理论基础 基础知识 深搜与广搜并查集最小生成树拓扑排序最短路算法 图论理论基础 图的基本概念 多个点连线 连通性 表示节点的连通情况 无向图 连通图非连通图连通分量&#xff1a;极…

Godot开发框架探索#2

前言 距离上次发文又又又隔了很长一段时间。主要原因还是因为思绪在徘徊&#xff0c;最近纠结的点有以下几个&#xff1a;1.渴求一个稳定的Godot开发框架&#xff1b;2.要不要使用更轻量的开发框架&#xff0c;或者直接写引擎&#xff1b; 3.对自己想做的游戏品类拿不定主意。…

机试题——最佳检测序列

题目描述 有一家云存储服务提供商&#xff0c;他们家的核心产品是一个可扩展的分布式存储系统。他们的客户使用他们的服务来存储和管理各种数据&#xff0c;包括文档、图片、视频等。由于客户对数据的可靠性和可用性要求非常高&#xff0c;他们需要提供高可用性的存储服务&…

Mybatis之常用动态Sql语句

数据库结构、实体类 public class Youth {private Integer id;private String username;private Date birthday;private Character sex;private String address;private Integer age;public Youth(Integer id, String username, Date birthday, Character sex, String address)…

拥抱开源,助力创新:IBM永久免费云服务器助力开源项目腾飞

近年来&#xff0c;开源项目蓬勃发展&#xff0c;为全球科技进步做出了巨大贡献。然而&#xff0c;服务器成本高昂常常成为开源项目的巨大障碍。许多优秀的项目因缺乏资源而难以持续发展&#xff0c;甚至夭折。令人振奋的是&#xff0c;IBM云计算平台推出了一项重磅活动&#x…

2025年React前端最新面试题整理(记录2025.2月面试合集)

以下是一些2025年 React 前端面试中常见的问题,涵盖了基础知识、进阶概念以及实际应用: 基础知识 什么是 React?它的核心理念是什么?解释组件的概念,以及函数组件和类组件的区别。什么是 JSX?它有什么优点?如何在 React 中管理状态?什么是 props?它与 state 有何不同…

MySQL数据库索引视图练习

一.练习目标 二.实现目标 (1)新建并使用数据库&#xff08;mydb15_indexstu&#xff09; (2)新建表&#xff08;Student&#xff0c;Course&#xff0c;SC&#xff09; Strudent&#xff1a; Course&#xff1a; SC&#xff1a; (3)处理表 1.修改Student表中年龄&#x…

Unity3D开发之2019.4.5f1版本IPointerClickHandler Bug

实际代码测试ui物体挂载的脚本里&#xff1a; 如果实现IPointerDownHandler和IPointerClickHandler接口&#xff0c;则会触发OnPointerClick和OnPointerDown函数调用。如果只实现IPointerClickHandler接口&#xff0c;则不会触发OnPointerClick函数调用。如果只实现IPointerDo…