【数据结构-图】最短路径

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

  • 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
  • 导航
    • 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
    • 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
    • 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

博客目录

    • 一.Dijkstra
      • 1.Dijkstra 简介
      • 2.有向无环图
      • 3.算法描述
      • 4.java 实现
      • 5.优化改进
      • 6.存在问题
    • 二.Bellman-Ford
      • 1.java 实现
      • 2.负环
    • 三.Floyd-Warshall
      • 1.负环图
      • 2.java 实现
      • 3.负环

一.Dijkstra

1.Dijkstra 简介

image-20230925193327109

Edsger Wybe Dijkstra

艾兹格·维布·迪克斯特拉(Edsger Wybe Dijkstra,/ˈdaɪkstrə/ DYKE-strə;荷兰语:[ˈɛtsxər ˈʋibə ˈdɛikstra] 1930 年 5 月 11 日-2002 年 8 月 6 日)是一位荷兰计算机科学家、程序员、软件工程师、系统科学家和科学散文家。他因对开发结构化编程语言做出的基础贡献而获得了 1972 年的图灵奖,并担任德克萨斯大学奥斯汀分校的斯伦贝谢百年计算机科学主席,任职时间从 1984 年到 2000 年。在他于 2002 年去世前不久,他因其在程序计算的自稳定性方面的工作而获得了 ACM PODC 分布式计算有影响力论文奖。为了纪念他,该年度奖项在接下来的一年更名为迪克斯特拉奖。

迪克斯特拉在计算机科学领域的贡献

  1. 最短路径算法,也称为迪克斯特拉算法,现代计算机科学本科课程中广泛教授
  2. Shunting yard 算法
  3. THE OS 操作系统
  4. 银行家算法
  5. 用于协调多个处理器和程序的信号量构造
  6. 在分布式计算领域提出概念:自稳定性

2.有向无环图

7
9
14
9
2
15
11
6
1
2
3
4
5
6

3.算法描述

算法描述:

  1. 将所有顶点标记为未访问。创建一个未访问顶点的集合。
  2. 为每个顶点分配一个临时距离值
    • 对于我们的初始顶点,将其设置为零
    • 对于所有其他顶点,将其设置为无穷大。
  3. 每次选择最小临时距离的未访问顶点,作为新的当前顶点
  4. 对于当前顶点,遍历其所有未访问的邻居,并更新它们的临时距离为更小
    • 例如,1->6 的距离是 14,而 1->3->6 的距离是 11。这时将距离更新为 11
    • 否则,将保留上次距离值
  5. 当前顶点的邻居处理完成后,把它从未访问集合中删除

4.java 实现

public class Dijkstra {public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");v1.edges = List.of(new Edge(v3, 9), new Edge(v2, 7), new Edge(v6, 14));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));List<Vertex> graph = List.of(v1, v2, v3, v4, v5, v6);dijkstra(graph, v1);}private static void dijkstra(List<Vertex> graph, Vertex source) {ArrayList<Vertex> list = new ArrayList<>(graph);source.dist = 0;while (!list.isEmpty()) {// 3. 选取当前顶点Vertex curr = chooseMinDistVertex(list);// 4. 更新当前顶点邻居距离updateNeighboursDist(curr, list);// 5. 移除当前顶点list.remove(curr);}for (Vertex v : graph) {System.out.println(v.name + " " + v.dist);}}private static void updateNeighboursDist(Vertex curr, ArrayList<Vertex> list) {for (Edge edge : curr.edges) {Vertex n = edge.linked;if (list.contains(n)) {int dist = curr.dist + edge.weight;if (dist < n.dist) {n.dist = dist;}}}}private static Vertex chooseMinDistVertex(ArrayList<Vertex> list) {Vertex min = list.get(0);for (int i = 1; i < list.size(); i++) {if (list.get(i).dist < min.dist) {min = list.get(i);}}return min;}}

5.优化改进

改进 - 优先级队列

  1. 创建一个优先级队列,放入所有顶点(队列大小会达到边的数量)
  2. 为每个顶点分配一个临时距离值
    • 对于我们的初始顶点,将其设置为零
    • 对于所有其他顶点,将其设置为无穷大。
  3. 每次选择最小临时距离的未访问顶点,作为新的当前顶点
  4. 对于当前顶点,遍历其所有未访问的邻居,并更新它们的临时距离为更小,若距离更新需加入队列
    • 例如,1->6 的距离是 14,而 1->3->6 的距离是 11。这时将距离更新为 11
    • 否则,将保留上次距离值
  5. 当前顶点的邻居处理完成后,把它从队列中删除
public class DijkstraPriorityQueue {public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");v1.edges = List.of(new Edge(v3, 9), new Edge(v2, 7), new Edge(v6, 14));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));List<Vertex> graph = List.of(v1, v2, v3, v4, v5, v6);dijkstra(graph, v1);}private static void dijkstra(List<Vertex> graph, Vertex source) {PriorityQueue<Vertex> queue = new PriorityQueue<>(Comparator.comparingInt(v -> v.dist));source.dist = 0;for (Vertex v : graph) {queue.offer(v);}while (!queue.isEmpty()) {System.out.println(queue);// 3. 选取当前顶点Vertex curr = queue.peek();// 4. 更新当前顶点邻居距离if(!curr.visited) {updateNeighboursDist(curr, queue);curr.visited = true;}// 5. 移除当前顶点queue.poll();}for (Vertex v : graph) {System.out.println(v.name + " " + v.dist + " " + (v.prev != null ? v.prev.name : "null"));}}private static void updateNeighboursDist(Vertex curr, PriorityQueue<Vertex> queue) {for (Edge edge : curr.edges) {Vertex n = edge.linked;if (!n.visited) {int dist = curr.dist + edge.weight;if (dist < n.dist) {n.dist = dist;n.prev = curr;queue.offer(n);}}}}}

6.存在问题

有负数边的情况

2
1
-2
1
v1
v2
v3
v4

按照 Dijkstra 算法,得出

  • v1 -> v2 最短距离 2
  • v1 -> v3 最短距离 1
  • v1 -> v4 最短距离 2

事实应当是

  • v1 -> v2 最短距离 2
  • v1 -> v3 最短距离 0
  • v1 -> v4 最短距离 1

二.Bellman-Ford

1.java 实现

public class BellmanFord {public static void main(String[] args) {// 正常情况/*Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");v1.edges = List.of(new Edge(v3, 9), new Edge(v2, 7), new Edge(v6, 14));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));List<Vertex> graph = List.of(v4, v5, v6, v1, v2, v3);*/// 负边情况/*Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");v1.edges = List.of(new Edge(v2, 2), new Edge(v3, 1));v2.edges = List.of(new Edge(v3, -2));v3.edges = List.of(new Edge(v4, 1));v4.edges = List.of();List<Vertex> graph = List.of(v1, v2, v3, v4);*/// 负环情况Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");v1.edges = List.of(new Edge(v2, 2));v2.edges = List.of(new Edge(v3, -4));v3.edges = List.of(new Edge(v4, 1), new Edge(v1, 1));v4.edges = List.of();List<Vertex> graph = List.of(v1, v2, v3, v4);bellmanFord(graph, v1);}private static void bellmanFord(List<Vertex> graph, Vertex source) {source.dist = 0;int size = graph.size();// 1. 进行 顶点个数 - 1 轮处理for (int i = 0; i < size - 1; i++) {// 2. 遍历所有的边for (Vertex s : graph) {for (Edge edge : s.edges) {// 3. 处理每一条边Vertex e = edge.linked;if (s.dist != Integer.MAX_VALUE && s.dist + edge.weight < e.dist) {e.dist = s.dist + edge.weight;e.prev = s;}}}}for (Vertex v : graph) {System.out.println(v + " " + (v.prev != null ? v.prev.name : "null"));}}
}

2.负环

2
-4
1
1
v1
v2
v3
v4

如果在【顶点-1】轮处理完成后,还能继续找到更短距离,表示发现了负环

三.Floyd-Warshall

1.负环图

-2
4
3
2
-1
v1
v3
v2
v4

2.java 实现

public class FloydWarshall {public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");v1.edges = List.of(new Edge(v3, -2));v2.edges = List.of(new Edge(v1, 4), new Edge(v3, 3));v3.edges = List.of(new Edge(v4, 2));v4.edges = List.of(new Edge(v2, -1));List<Vertex> graph = List.of(v1, v2, v3, v4);/*直接连通v1  v2  v3  v4v1  0   ∞   -2  ∞v2  4   0   3   ∞v3  ∞   ∞   0   2v4  ∞   -1  ∞   0k=0 借助v1到达其它顶点v1  v2  v3  v4v1  0   ∞   -2  ∞v2  4   0   2   ∞v3  ∞   ∞   0   2v4  ∞   -1  ∞   0k=1 借助v2到达其它顶点v1  v2  v3  v4v1  0   ∞   -2  ∞v2  4   0   2   ∞v3  ∞   ∞   0   2v4  3   -1  1   0k=2 借助v3到达其它顶点v1  v2  v3  v4v1  0   ∞   -2  0v2  4   0   2   4v3  ∞   ∞   0   2v4  3   -1  1   0k=3 借助v4到达其它顶点v1  v2  v3  v4v1  0   -1   -2  0v2  4   0   2   4v3  5   1   0   2v4  3   -1  1   0*/floydWarshall(graph);}static void floydWarshall(List<Vertex> graph) {int size = graph.size();int[][] dist = new int[size][size];Vertex[][] prev = new Vertex[size][size];// 1)初始化for (int i = 0; i < size; i++) {Vertex v = graph.get(i); // v1 (v3)Map<Vertex, Integer> map = v.edges.stream().collect(Collectors.toMap(e -> e.linked, e -> e.weight));for (int j = 0; j < size; j++) {Vertex u = graph.get(j); // v3if (v == u) {dist[i][j] = 0;} else {dist[i][j] = map.getOrDefault(u, Integer.MAX_VALUE);prev[i][j] = map.get(u) != null ? v : null;}}}print(prev);// 2)看能否借路到达其它顶点/*v2->v1          v1->v?dist[1][0]   +   dist[0][0]dist[1][0]   +   dist[0][1]dist[1][0]   +   dist[0][2]dist[1][0]   +   dist[0][3]*/for (int k = 0; k < size; k++) {for (int i = 0; i < size; i++) {for (int j = 0; j < size; j++) {
//                    dist[i][k]   +   dist[k][j] // i行的顶点,借助k顶点,到达j列顶点
//                    dist[i][j]                  // i行顶点,直接到达j列顶点if (dist[i][k] != Integer.MAX_VALUE &&dist[k][j] != Integer.MAX_VALUE &&dist[i][k] + dist[k][j] < dist[i][j]) {dist[i][j] = dist[i][k] + dist[k][j];prev[i][j] = prev[k][j];}}}
//            print(dist);}print(prev);}static void path(Vertex[][] prev, List<Vertex> graph, int i, int j) {LinkedList<String> stack = new LinkedList<>();System.out.print("[" + graph.get(i).name + "," + graph.get(j).name + "] ");stack.push(graph.get(j).name);while (i != j) {Vertex p = prev[i][j];stack.push(p.name);j = graph.indexOf(p);}System.out.println(stack);}static void print(int[][] dist) {System.out.println("-------------");for (int[] row : dist) {System.out.println(Arrays.stream(row).boxed().map(x -> x == Integer.MAX_VALUE ? "∞" : String.valueOf(x)).map(s -> String.format("%2s", s)).collect(Collectors.joining(",", "[", "]")));}}static void print(Vertex[][] prev) {System.out.println("-------------------------");for (Vertex[] row : prev) {System.out.println(Arrays.stream(row).map(v -> v == null ? "null" : v.name).map(s -> String.format("%5s", s)).collect(Collectors.joining(",", "[", "]")));}}}

3.负环

如果在 3 层循环结束后,在 dist 数组的对角线处(i==j 处)发现了负数,表示出现了负环

觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

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

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

相关文章

华为乾坤区县教育安全云服务解决方案(2)

本文承接&#xff1a; https://blog.csdn.net/qq_37633855/article/details/133276200?spm1001.2014.3001.5501 重点讲解华为乾坤区县教育安全云服务解决方案的部署流程。 华为乾坤区县教育安全云服务解决方案&#xff08;2&#xff09; 课程地址解决方案部署整体流程组网规划…

曲线救国-通过Magisk安装burp证书到系统根目录

0x01前言 需要对某APP做渗透测试&#xff0c;但该APP做了限制&#xff1a;不信任用户证书。因此需要将burp证书导入到存放系统证书目录下。虽然手机装了Magic&#xff0c;但似乎root有点问题。其挂载有问题&#xff0c;导致无法将 最初尝试&#xff1a;mount -o rw,remount -t…

【牛客网】排序子序列

代码 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);int n in.nextInt();int[] array new int[n1];//此处n1 防止后面判断i1下标时数组越…

python中使用matplotlib绘图

一、背景 当我们在写python程序时&#xff0c;不可避免的需要将数据可视化&#xff0c;也就是绘制出数据的曲线图&#xff0c;以便我们更直观的观察数据间的变化&#xff0c;以及方便对比。此时就要用到matplotlib库了。 matplotlib官方给出的定义是&#xff1a; 翻译过来也就…

云HIS 医院综合运营管理系统源码

医院管理信息系统&#xff08;HIS&#xff09;是医院基本、重要的管理系统&#xff0c;是医院大数据的基础。 基于云计算的云医疗信息系统&#xff08;云HIS&#xff09;。以SaaS的方式提供服务&#xff0c;系统遵循服务化、模块化原则开发&#xff0c;具有强大的可扩展性&…

深度学习-学习率调度,正则化,dropout

正如前面我所说的&#xff0c;各种优化函数也依赖于学习率&#xff0c;保持学习率恒定总是有所限制&#xff0c;在执行梯度下降过程中&#xff0c;我们可以使用各种方法来调节训练过程的学习率&#xff0c;这里只是稍微介绍一下&#xff0c;不会写代码实现的。同时&#xff0c;…

Apache DolphinScheduler 在奇富科技的首个调度异地部署实践

奇富科技&#xff08;原360数科&#xff09;是人工智能驱动的信贷科技服务平台&#xff0c;致力于凭借智能服务、AI研究及应用、安全科技&#xff0c;赋能金融机构提质增效&#xff0c;助推普惠金融高质量发展&#xff0c;让更多人享受到安全便捷的金融科技服务。作为国内领先的…

Java BigDecimal 详解

目录 一、BigDecimal 1、简介 2、构造器描述 3、方法描述 4、使用 一、BigDecimal float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算&#xff0c;这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而&#xff0c;它…

树莓派(Linux系统通用)交叉编译(环境搭建、简单使用)

概念 交叉编译是指在一台计算机上编译运行在另一台计算机上的程序。&#xff08;编译是指&#xff0c;在一个平台上生成在该平台上的可执行程序&#xff09;通常情况下&#xff0c;编译器和目标平台的架构是不同的&#xff0c;例如&#xff0c;在一台x86平台上编译运行在ARM平…

数据结构-----二叉树的创建和遍历

目录 前言 二叉树的链式存储结构 二叉树的遍历 1.前序遍历 2.中序遍历 3.后序遍历 二叉树的创建 创建一个新节点的函数接口 1.创建二叉树返回根节点 2.已有根节点&#xff0c;创建二叉树 3.已有数据&#xff0c;创建二叉树 前言 在此之前我们学习了二叉树的定义和储…

6种最常用的3D点云语义分割AI模型对比

由于增强现实/虚拟现实的发展及其在计算机视觉、自动驾驶和机器人领域的广泛应用&#xff0c;点云学习最近引起了人们的关注。 深度学习已成功用于解决 2D 视觉问题&#xff0c;然而&#xff0c;由于其处理面临独特的挑战&#xff0c;深度学习技术在点云上的使用仍处于起步阶段…

【Vue3】v-model

v-model 基本用法 prop: modelValue 事件&#xff1a;update:modelValue <!-- App.vue --><template><div><h1>我是父组件</h1><div>isShow: {{ isShow }}</div><div><button click"isShow !isShow">开关&…

nodejs+vue大学食堂订餐系统elementui

可以查看会员信息&#xff0c;录入新的会员信息&#xff0c;对会员的信息进行管理。 网站管理模块对整个网站中的信息进行管理&#xff0c;可以查看会员留在留言栏中的信息&#xff0c;设置网站中的参数等。用户管理模块主要实现用户添加、用户修改、用户删除等功能。 近年来&…

Oracle实现主键字段自增

Oracle实现主键自增有4种方式&#xff1a; Identity Columns新特性自增&#xff08;Oracle版本≥12c&#xff09;创建自增序列&#xff0c;创建表时&#xff0c;给主键字段默认使用自增序列创建自增序列&#xff0c;使用触发器使主键自增创建自增序列&#xff0c;插入语句&…

MySQL MHA 高可用

目录 1 MySQL MHA 1.1 什么是 MHA 1.2 MHA 的组成 1.3 MHA 的特点 2 搭建 MySQL MHA 2.1 Master、Slave1、Slave2 节点上安装 mysql5.7 2.2 修改 Master、Slave1、Slave2 节点的主机名 2.3 修改 Master、Slave1、Slave2 节点的 Mysql主配置文件/etc/my.cnf 2.4 在 Mast…

图像采集卡在应用程序的重要性概述

达到最大吞吐量是工业和工厂自动化的关键标准之一。提高传感器分辨率和帧速率有助于实现目标&#xff0c;但会限制带宽&#xff0c;并带来新的传输问题。图像采集卡是将相机连接到PC的最方便、最可靠的方式&#xff0c;在工业环境中使用图像采集卡为高速应用带来了特定的好处&a…

[C++ 网络协议] 异步通知I/O模型

1.什么是异步通知I/O模型 如图是同步I/O函数的调用时间流&#xff1a; 如图是异步I/O函数的调用时间流&#xff1a; 可以看出&#xff0c;同异步的差别主要是在时间流上的不一致。select属于同步I/O模型。epoll不确定是不是属于异步I/O模型&#xff0c;这个在概念上有些混乱&a…

【深度学习】【Opencv】Python/C++调用onnx模型【基础】

【深度学习】【Opencv】python/C调用onnx模型【基础】 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【Opencv】python/C调用onnx模型【基础】前言Python版本OpenCVWindows平台安装OpenCVopencv调用onnx模型 C版本OpenCVWindows平…

spring bean实例化过程及顺序

spring bean的初始化从doCreateBean方法开始&#xff0c;依次会调用下面三个方法执行bean的初始化。大部分方法都在AbstractAutowireCapableBeanFactory类中。 实例化 createBeanInstance()方法根据BeanDef获取bean对应的class通过反射调用构造函数进行bean的实例化。 这里会…

视频汇聚平台EasyCVR从一分屏切换到四分屏后加载记录显示黑屏该如何解决?

视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等&#xff0c;视频智能分析平台EasyCVR融合性强、开放度…