(Java)数据结构——图(第七节)Folyd实现多源最短路径

前言

本博客是博主用于复习数据结构以及算法的博客,如果疏忽出现错误,还望各位指正。

Folyd实现原理

中心点的概念

感觉像是充当一个桥梁的作用

还是这个图

我们常在一些讲解视频中看到,就比如dist(-1),这是原始的邻接矩阵

dist(0),就是A充当中心点

这时候就是打比方,我D->E,A作为中心点之后,这一轮就是看D->A->E的距离相较之前是否最小,所以,A->A->B多次一举,所以pass,X->A->A也是多此一举,所以pass,对角线别动X->A->X又回到自己PASS。一来三个pass,差不多如图。我们只需要剩下的就可以。

打比方B->C,那么加入A之后就是B->A->C=BA+AC=8+1=9,相比于之前的6,大了,所以不换不更新。

B->E,那么加入A之后就是B->A->E,BA+AE=8+INF,直接pass遇到不通的情况。

遍历完B,到C继续重复步骤更新……即可,脑力有限,就不多解释了。

这样我每个点都充当一次中心点下来,我的最短路径也出来了。

Folyd实现代码

Folyd的代码形式十分简单,如果比赛中看寻找最短路径,嫌Dijkstra算法麻烦的话,直接试试Folyd看看能不能过,不能再说单源的。以下是主要实现代码。

public int[][] Folyd(){int N = vertexList.size();int[][] edges = new int[N][N];//新开个二维数组,防止数据被动//edges[i] = this.edges[i],这样是不行的,因为java的引用for(int i = 0;i<N;i++){for(int j=0;j<N;j++){edges[i][j] = this.edges[i][j];}}//弗洛伊德算法就是要求整个的for(int k = 0;k<N;k++){//中心点for(int i = 0;i<N;i++){//哪个点//if(i==k) continue;for(int j = 0;j<N;j++){//到哪个点//if(j == k) continue;if(i == j) continue;if(edges[i][k] !=Integer.MAX_VALUE && edges[k][j] != Integer.MAX_VALUE){edges[i][j] = Math.min(edges[i][j], edges[i][k] + edges[k][j]);//当前的ij位置}}}}return edges;}

三层循环,代码中注释//掉的if就是我原理里面pass的东西。

以下是完整的实现代码,以及与迪杰斯特拉算法结果的比对。

//package GraphTest.Demo;import java.util.*;public class Graph{//这是一个图类/***基础属性***/int[][] edges;    //邻接矩阵存储边ArrayList<EData> to = new ArrayList<>();    //EData包含start,end,weight三个属性,相当于另一种存储方式,主要是为了实现kruskal算法定义的ArrayList<String> vertexList = new ArrayList<>();    //存储结点名称,当然你若想用Integer也可以,这个是我自己复习用的int numOfEdges;    //边的个数boolean[] isVisited;//构造器Graph(int n){this.edges = new int[n][n];//为了方便,决定讲结点初始化为INF,这也方便后续某些操作int INF = Integer.MAX_VALUE;for(int i=0;i<n;i++){Arrays.fill(edges[i],INF);}this.numOfEdges = 0;this.isVisited = new boolean[n];}//插入点public void insertVertex(String vertex){//看自己个人喜好,我这边是一个一个在主方法里插入点的名称vertexList.add(vertex);}//点的个数public int getNumOfVertex(){return vertexList.size();}//获取第i个节点的名称public String getVertexByIndex(int i){return vertexList.get(i);}//获取该节点的下标public int getIndexOfVertex(String vertex){return vertexList.indexOf(vertex);}//插入边public void insertEdge(int v1,int v2,int weight){//注意,这里是无向图edges[v1][v2] = weight;edges[v2][v1] = weight;this.numOfEdges++;//如果要用Kruskal算法的话这里+to.add(new EData(v1,v2,weight));    //加入from to这种存储方式}//边的个数public int getNumOfEdge(){return this.numOfEdges;}//得到点到点的权值public int getWeight(int v1,int v2){//获取v1和v2边的权重return edges[v1][v2];}//打印图public void showGraph(){for(int[] line:edges){System.out.println(Arrays.toString(line));}}//获取index行 第一个邻接结点public int getFirstNeighbor(int index){for(int i = 0;i < vertexList.size();i++){if(edges[index][i] != Integer.MAX_VALUE){return i;    //找到就返回邻接结点的坐标}}return -1;    //没找到的话,返回-1}//获取row行 column列之后的第一个邻接结点public int getNextNeighbor(int row,int column){for(int i = column + 1;i < vertexList.size();i++){if(edges[row][i] != Integer.MAX_VALUE){return i;    //找到就返回邻接结点的坐标}}return -1;    //没找到的话,返回-1}//DFS实现,先定义一个isVisited布尔数组确认该点是否遍历过public void DFS(int index,boolean[] isVisited){System.out.print(getVertexByIndex(index)+" ");    //打印当前结点isVisited[index] = true;//查找index的第一个邻接结点fint f = getFirstNeighbor(index);//while(f != -1){//说明有if(!isVisited[f]){//f没被访问过DFS(f,isVisited);    //就进入该节点f进行遍历}//如果f已经被访问过,从当前 i 行的 f列 处往后找f = getNextNeighbor(index,f);}}//考虑到连通分量,需要对所有结点进行一次遍历,因为有Visited,所以不用考虑冲突情况public void DFS(){for(int i=0;i<vertexList.size();i++){if(!isVisited[i]){DFS(i,isVisited);}}}public void BFS(int index,boolean[] isVisited){//BFS是由队列实现的,所以我们先创建一个队列LinkedList<Integer> queue = new LinkedList<>();System.out.print(getVertexByIndex(index)+" ");    //打印当前结点isVisited[index] =true;    //遍历标志turequeue.addLast(index);    //队尾加入元素int cur,neighbor;    //队列头节点cur和邻接结点neighborwhile(!queue.isEmpty()){//如果队列不为空的话,就一直进行下去//取出队列头结点下标cur = queue.removeFirst();    //可以用作出队//得到第一个邻接结点的下标neighbor = getFirstNeighbor(cur);//之后遍历下一个while(neighbor != -1){//邻接结点存在//是否访问过if(!isVisited[neighbor]){System.out.print(getVertexByIndex(neighbor)+" ");isVisited[neighbor] = true;queue.addLast(neighbor);}//在cur行找neighbor列之后的下一个邻接结点neighbor = getNextNeighbor(cur,neighbor);}}}//考虑到连通分量,需要对所有结点进行一次遍历,因为有Visited,所以不用考虑冲突情况public void BFS(){for(int i=0;i<vertexList.size();i++){if(!isVisited[i]){BFS(i,isVisited);}}}public  void prim(int begin){//Prim原理:从当前集合选出权重最小的邻接结点加入集合,构成新的集合,重复步骤,直到N-1条边int N = vertexList.size();//当前的集合 与其他邻接结点的最小值int[] lowcost = edges[begin];//记录该结点是从哪个邻接结点过来的int[] adjvex = new int[N];Arrays.fill(adjvex,begin);//表示已经遍历过了,isVisited置trueisVisited[begin] = true;for(int i =0;i<N-1;i++){//进行N-1次即可,因为只需要联通N-1条边//寻找当前集合最小权重邻接结点的操作int index = 0;int mincost = Integer.MAX_VALUE;for(int j = 0;j<N;j++){if(isVisited[j]) continue;if(lowcost[j] < mincost){//寻找当前松弛点mincost = lowcost[j];index = j;}}System.out.println("选择节点"+index+"权重为:"+mincost);isVisited[index] = true;System.out.println(index);//加入集合后更新的操作,看最小邻接结点是否更改for(int k = 0;k<N;k++){if(isVisited[k]) continue;//如果遍历过就跳过if(edges[index][k] < lowcost[k]){ //加入新的节点之后更新,检查原图的index节点,加入后,是否有更新的lowcost[k] = (edges[index][k]);adjvex[k] = index;}}}}//用于对之前定义的to进行排序public void toSort(){Collections.sort(this.to, new Comparator<EData>() {@Overridepublic int compare(EData o1, EData o2) {//顺序对就是升序,顺序不对就是降序,比如我现在是o1和o2传进来,比较时候o1在前就是升序,o1在后就是降序int result = Integer.compare(o1.weight,o2.weight);return result;}});}//并查集查找public int find(int x,int[] f){while(x!=f[x]){x = f[x];}return x;}//并查集合并public int union(int x,int y,int[] f){find(x,f);find(y,f);if(x!=y){f[x] = y;return y;}return -1;    //如果一样的集合就返回-1}public  ArrayList<Integer> kruskal(){//kruskal是对form to weight这种结构的类进行排序,然后选取最短的一条边,看是否形成回路,加入toSort();    //调用toSort进行排序//由于要判断是否形成回路,我们可以用DFS或者BFS,因为之前都写过,所以我们在这用并查集//初始化并查集int[] f = new int[vertexList.size()];for(int i = 0;i<vertexList.size();i++){f[i] = i;}ArrayList<Integer> res = new ArrayList<>();int count = 0;for(int i = 0;count != vertexList.size()-1 && i<this.to.size();i++){//之后就是开始取边了EData temp = this.to.get(i);if(union(temp.start,temp.end,f)!=-1){//如果查到不是一个集,就可以添加//这里都加进来是方便看哪个边res.add(temp.start);res.add(temp.end);count++;}}return res;    //最后把集合返回去就行}public int[] Dijkstra(int begin){int N = vertexList.size();//到其他点的最短路径,动态更新,直到最后返回int[] dist = new int[N];for(int i=0;i<N;i++){ //进行一下拷贝,以免更改核心数据dist[i] = edges[begin][i];}//System.out.println(Arrays.toString(dist));isVisited[begin] = true;    //该点已经遍历过int[] path = new int[N];    //记录这个点从哪来的,到时候在path里寻找就行//比如path 2 1 1 1 1,那么A就是从C来的,然后去C,C是从B来的,B是从B来的,OK结束,路径出来Arrays.fill(path,begin);for(int i = 0;i<N;i++){//几个点遍历多少次int min = Integer.MAX_VALUE;int index = 0;for(int j = 0;j<N;j++){//寻找当前的最短路径if(!isVisited[j]){if(dist[j] < min){min = dist[j];index = j;}}}isVisited[index] = true;    //置为遍历过for(int k = 0;k<N;k++){//新加入点后,看min+edges[新加点的那一行],看是不是比以前的小,小就换了if(!isVisited[k] && edges[index][k]!=Integer.MAX_VALUE){//此处格外注意,因为Integer.MAX_VALUE再+就变成负的了,所以一定要注意if(dist[index]+edges[index][k] < dist[k]){dist[k] = dist[index]+edges[index][k];path[k] = index;}}}//找到了之后呢}//System.out.println(Arrays.toString(dist));//System.out.println(Arrays.toString(path));return dist;     //返回的是到每个点的最小路径}public int[][] Folyd(){int N = vertexList.size();int[][] edges = new int[N][N];for(int i = 0;i<N;i++){for(int j = 0;j<N;j++){edges[i][j] = this.edges[i][j];}}//弗洛伊德算法就是要求整个的for(int k = 0;k<N;k++){//中心点for(int i = 0;i<N;i++){//哪个点//if(i==k) continue;for(int j = 0;j<N;j++){//到哪个点//if(j == k) continue;if(i == j) continue;if(edges[i][k] !=Integer.MAX_VALUE && edges[k][j] != Integer.MAX_VALUE){edges[i][j] = Math.min(edges[i][j], edges[i][k] + edges[k][j]);//当前的ij位置}}}}return edges;}public static void main(String[] args) {int n = 5;String[] Vertexs ={"A","B","C","D","E"};//创建图对象Graph graph = new Graph(n);for(String value:Vertexs){graph.insertVertex(value);}graph.insertEdge(0,1,8);graph.insertEdge(0,2,1);graph.insertEdge(1,2,6);graph.insertEdge(1,3,3);graph.insertEdge(1,4,5);graph.insertEdge(3,4,8);
//        graph.showGraph();
//
//        graph.DFS(1, graph.isVisited);
//        System.out.println();
//        graph.DFS();//再求求所有的,看有没有剩下的
//        System.out.println();
//        Arrays.fill(graph.isVisited,false);
//        graph.BFS(1, graph.isVisited);
//        System.out.println();
//        Arrays.fill(graph.isVisited,false);
//        graph.BFS();
//        System.out.println();
//        Arrays.fill(graph.isVisited,false);
//        graph.prim(2);
//        graph.toSort();
//        for(EData i : graph.to){
//            System.out.println(i.toString());
//        }
//        System.out.println(graph.kruskal().toString());;
//        Arrays.fill(graph.isVisited,false);for(int i = 0;i<graph.getNumOfVertex();i++){//每个点的到其他点的最短路径只需要遍历一遍即可,时间复杂度On3Arrays.fill(graph.isVisited,false);System.out.println(Arrays.toString(graph.Dijkstra(i)));;}for(int[] i : graph.Folyd()){System.out.println(Arrays.toString(i));}}
}class EData{//当然,这是为了方便,直接记录结点下标,而不记录像"A"这种int start;int end;int weight;EData(int start,int end,int weight){this.start = start;this.end = end;this.weight = weight;}@Overridepublic String toString() {return "EData{" +"start=" + start +", end=" + end +", weight=" + weight +'}';}
}

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

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

相关文章

volta(轻松切换管理Node.js版本)

Node.js版本管理 Volta提供了一个简单直观的命令行界面&#xff0c;可以轻松地安装、卸载、更新和切换Node.js版本。 Volta 既可以全局使用&#xff0c;也可以在项目级别使用&#xff0c;可以为每个项目单独设置node版本&#xff0c;nvm不行。 下载安装Volta 参考&#xff1a; …

为什么要“挺”鸿蒙?

鸿蒙到底是什么&#xff1f; 随着5G、物联网等技术的快速发展&#xff0c;智能终端设备的应用场景也越来越广泛。为了满足不同设备间的互联互通需求&#xff0c;华为在2019年推出了自主研发的操作系统——鸿蒙OS。值得关注的是&#xff0c;这也是首款国产操作系统。 要了解鸿…

【可视化大屏开发】18. 加餐-ECharts+百度地图API实现热力图

ECharts结合百度地图API能获得更好的使用体验。 效果展示 放大后的效果 切换卫星地图模式 实现步骤 1. 通过Python实现GPS数据模拟 2. 通过IDEA开发地图 通过Python实现GPS数据模拟 import random from math import cos, sin, radians, sqrt import jsondef generate_random…

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记13:RTC实时时钟

系列文章目录 嵌入式|蓝桥杯STM32G431&#xff08;HAL库开发&#xff09;——CT117E学习笔记01&#xff1a;赛事介绍与硬件平台 嵌入式|蓝桥杯STM32G431&#xff08;HAL库开发&#xff09;——CT117E学习笔记02&#xff1a;开发环境安装 嵌入式|蓝桥杯STM32G431&#xff08;…

春游江淮 请来池州 | “香隅”有约 向春而行

伴随着天气逐渐回暖,香隅镇各景点人气持续高涨,迎来了春节后的第一波客流高峰,游客们到香隅赏春光、闻花香、游景区,欣赏“香隅”有约的独特魅力。 淡黄、橙色、紫色、粉色……在香隅镇休闲农业观光园景区内,100多亩七彩油菜迎风招摇,煞是好看,不少周边游客被景区的春花绕树、绿…

Linux下记一次系统日志中大量出现Started Session * of user root 查找和解决办法

安装的纯净版centos 系统日志中大量出现出现 Started Session * of user root。系统启动会话 很多用户在会在centos服务器日志中中发现大量系统启动会话&#xff0c;有频率的出现系统日志&#xff0c;这个信息并不是报错信息&#xff0c;但是大量这个又不方便你分析日志&#…

git push报错remote: Please remove the file from history and try again

原因&#xff1a;上传文件超过100M&#xff0c;找到此文件删除即可。 1、查看是哪个文件过大&#xff0c;此处对用红框里面的 a6de1336c67c3bac77757c5eff8c8001823f7c92&#xff0c;得到具体的文件名称 git rev-list --objects --all | grep a6de1336c67c3bac77757c5eff8c80…

2024Mathorcup(妈妈杯)数学建模C题python代码+数据教学

2024Mathorcup数学建模挑战赛&#xff08;妈妈杯&#xff09;C题保姆级分析完整思路代码数据教学 C题题目&#xff1a;物流网络分拣中心货量预测及人员排班 因为一些不可抗力&#xff0c;下面仅展示部分代码&#xff08;很少部分部分&#xff09;和部分分析过程&#xff0c;其…

【opencv】示例-detect_blob.cpp

// 导入所需的OpenCV头文件 #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> #include <opencv2/features2d.hpp> // 导入向量和映射容器 #include <vector> #include <map> // 导入输入输出…

【RV1106的ISP使用记录之二】设备树的构建

基于MIPI接口的两种摄像头接入方式&#xff0c;理清楚各链路关系&#xff0c;方便后续的开发调试工作&#xff0c;先上一张图&#xff0c;后面再补充解释。

Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey

Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey PDF: https://arxiv.org/pdf/2403.14608.pdf 1 概述 大型模型在多个领域取得了显著进展&#xff0c;但它们的大规模参数带来了高昂的计算成本。这些模型需要大量资源来执行&#xff0c;尤其是在针…

强化学习基础概念入门

文章目录 1. 什么是强化学习&#xff1f;2. 强化学习的基本元素3. 相关衍生元素3.1 策略(Policy)3.2 状态转移(State Transition)3.3 回报(Return)3.4 价值函数(Value Function) 4. 算法分类4.1 按环境是否已知划分4.2 按学习方式划分4.3 按学习目标划分 参考资料 1. 什么是强化…

农业小型气象站解析

TH-NQ12农业小型气象站&#xff0c;作为现代智慧农业体系的重要组成部分&#xff0c;以其独特的优势在农业生产中发挥着不可或缺的作用。这种专为农业领域设计的小型气象站&#xff0c;不仅具备高度自动化和智能化的特点&#xff0c;而且能够实时监测和记录农田环境中的多种气象…

QT:QMainWindow、ui界面、资源文件的添加、信号和槽

1.练习&#xff1a;使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(…

[python] Numpy库用法(持续更新)

先导入一下 import numpy as np 一、np.random用法 生成随机整数&#xff1a;np.random.randint(low, high, size) low: 最小值high: 最大值size: 生成的数组大小&#xff08;可以是多维&#xff0c;下面同理&#xff09; 生成随机浮点数&#xff1a;np.random.uniform(low, …

Ubuntu 22.04进行远程桌面连接

文心一言 Ubuntu 22.04进行远程桌面连接&#xff0c;无论是连接到Windows 10还是另一个Ubuntu 22.04&#xff0c;都可以通过不同的方式实现。以下是具体的步骤&#xff1a; 连接到Windows 10 在Windows 10上开启远程桌面功能&#xff1a;首先&#xff0c;需要在Windows 10上…

ViT:拉开Trasnformer在图像领域正式挑战CNN的序幕 | ICLR 2021

论文直接将纯Trasnformer应用于图像识别&#xff0c;是Trasnformer在图像领域正式挑战CNN的开山之作。这种简单的可扩展结构在与大型数据集的预训练相结合时&#xff0c;效果出奇的好。在许多图像分类数据集上都符合或超过了SOTA&#xff0c;同时预训练的成本也相对较低   来源…

深入理解MD5算法:原理、应用与安全

title: 深入理解MD5算法&#xff1a;原理、应用与安全 date: 2024/4/11 20:55:57 updated: 2024/4/11 20:55:57 tags: MD5算法数据安全哈希函数摘要算法安全漏洞SHA算法密码学 第一章&#xff1a;引言 导言 在当今数字化时代&#xff0c;数据安全和完整性变得至关重要。消息…

【学习路径】AI入门路线分享

近期整理飞书文档&#xff0c;一些权限被关掉了。看好多人在申请访问这个飞书文档&#xff0c;于是把它单独拿出来放在CSDN上&#xff0c;供大家参考~ 原视频地址&#xff1a;AI&#xff1a;从小白到入门&#xff0c;超详细人工智能成长路径分享_哔哩哔哩_bilibili 文章目录 1.…

HarmonyOS实战开发-证书管理、如何实现对签名数据进行校验功能。

介绍 本示例使用了ohos.security.certManager相关接口实现了对签名数据进行校验的功能。 实现场景如下&#xff1a; 1&#xff09;使用正确的原始数据和签名数据进行签名校验场景&#xff1a;模拟服务端对签名数据进行校验&#xff0c;验证客户端身份和原始数据完整性。 2&…