C语言-数据结构 弗洛伊德算法(Floyd)邻接矩阵存储

news2024/12/23 4:04:06

        弗洛伊德算法相比迪杰斯特拉相似的地方都是遍历邻接矩阵不断调整最短路径的信息,并且两种算法面对多源最短路径的时间复杂度都是O(n^3),Floyd采用的是动态规划而Dijkstra是采用贪心的思想。在Floyd中我们将创建两个数组进行辅助,一个path二维数组用于存储路径信息,一个table二维数组用于记录更新各结点间的最短路径长度,table的初始化就是简单的把邻接矩阵的信息复制过来,整个算法都是在这个table表中不断更新,代码中第一层for循环是控制中转结点,另外两行就是遍历整个table二位数组,table[v][k]表示辅助列,table[k][w]表示辅助行,辅助行与辅助列由中转结点控制在整个table表的主对角线上运动,table[v][w]当前扫描的邻接结点信息,如果当前邻接结点的权值大于对应的(辅助行+辅助列的权值和),那么说明找到更短的路径需要进行更新权值,当前邻接结点信息改为(辅助行+辅助列的权值和),同时更新路径信息为中转结点(即前驱顶点),代码中path[v][k]存储了对应的中转结点信息,利用它更新当前邻接结点的前驱结点(对应的中转结点)信息,当循环结束整个图各顶点到达其他所有顶点的最短距离就计算完成了,最后我们打印table矩阵的上三角部分因为两个结点的表示可以用一个方向就行,例如A->F打印了就可以表示F->A,并不需求遍历完全部table矩阵信息,同时打印路径信息的第二个for循环有个+1操作是为了避免打印AA、BB这种自己到自己的路径,也就是不打印主对角线,path路径信息的存储也同样用到并查集的部分思想在上一篇博文提过,在代码中通过不断循环path路径能够找到它的前驱结点一步步把所有路径结点信息找到,相比迪杰斯特拉倒着找结点信息,这里我们可以之间通过path二维数组顺序查找到路径信息,也是非常巧妙的!

 我们将创建下面的无向权值图:

84ef03cba4ba478383b338ae5884012a.png

  邻接矩阵的绘制还是手动赋值上三角,并通过矩阵对称性生成整个邻接矩阵,其中最小生成树中需要用到权值,对应原本有边的地方之前我是用1表示,现在改成边对应的权值,之前的0表示没有边,现在改成99表示为无穷,其实应该换成更大的值以确保树的边权值都小于这个最大值,但为了方便对齐显示看邻接矩阵,就使用了比本图中各边长较大的99来表示最大值。

9eefaa5c866742cbb239f5f9de2aff7d.png

Floyd算法代码:

//存储所有顶点的路径信息
typedef int Patharc[MAXVEX][MAXVEX];
//最短路径表copy邻接矩阵,不断扫描更新各顶点相互间的最短距离
typedef int ShortestPathTable[MAXVEX][MAXVEX];
// Floyd算法实现
void Floyd(MGraph G, Patharc path, ShortestPathTable table) {
	int v, w, k;
	// 初始化表和路径矩阵
	for (v = 0; v < G.numNodes; v++) {
		for (w = 0; w < G.numNodes; w++) {
			table[v][w] = G.arc[v][w];  // 初始化最短路径表
			if (G.arc[v][w] < INFINITY) {
				path[v][w] = w;  // 有直接边时,路径是目标顶点
			}
			else {
				path[v][w] = -1; // 如果没有边,则设为 -1
			}
		}
	}

	// Floyd算法的核心计算
	for (k = 0; k < G.numNodes; k++) {  // 遍历每个顶点作为中间顶点
		for (v = 0; v < G.numNodes; v++) {  // 遍历起点
			for (w = 0; w < G.numNodes; w++) {  // 遍历终点
				// 如果通过顶点 k 的路径更短,则更新路径和最短路径表
				if (table[v][w] > table[v][k] + table[k][w]) {
					table[v][w] = table[v][k] + table[k][w];
					path[v][w] = path[v][k];
				}
			}
		}
	}

	// 打印各顶点间的最短路径
	printf("各顶点间最短路径如下:\n");
	for (v = 0; v < G.numNodes; v++) {
		for (w = v + 1; w < G.numNodes; w++) {  // 遍历每对顶点
			//Array数组存储顶点ABCDEFGH
			printf("%c-%c weight:%d\n", Array[v], Array[w], table[v][w]);
			k = path[v][w];  // 从起点到终点的路径
			printf("path:%d", v);
			while (k != w) {  // 路径输出
				printf("->%d", k);
				k = path[k][w];
			}
			printf("->%d\n", w);
		}
		printf("\n");
	}
}

完整代码(包括邻接矩阵的创建、Floyd算法)

#include "stdio.h"    
#include "stdlib.h"   
#include "math.h"  
#include "time.h"

// 禁用特定的警告
#pragma warning(disable:4996)

// 定义一些常量和数据类型
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXVEX 8 /* 最大顶点数,用户定义 */
#define MAXEDGE 10 /* 最大边数,用户定义 */
#define GRAPH_INFINITY 99 /* 用0表示∞,表示不存在边 */

/* 定义状态、顶点和边的类型 */
typedef int Status;  /* Status是函数的返回类型,如OK表示成功 */
typedef char VertexType; /* 顶点的类型,用字符表示 */
typedef int EdgeType; /* 边上的权值类型,用整数表示 */
typedef int Boolean; /* 布尔类型 */
// 定义顶点标签
char Array[] = "ABCDEFGHI";

/* 图的邻接矩阵结构体 */
typedef struct
{
	VertexType vexs[MAXVEX]; /* 顶点表 */
	EdgeType arc[MAXVEX][MAXVEX]; /* 邻接矩阵,表示边的权值 */
	int numNodes, numEdges; /* 图中当前的顶点数和边数 */
} MGraph;

//存储所有顶点的路径信息
typedef int Patharc[MAXVEX][MAXVEX];
//最短路径表copy邻接矩阵,不断扫描更新各顶点相互间的最短距离
typedef int ShortestPathTable[MAXVEX][MAXVEX];

/* 创建一个无向网图的邻接矩阵表示 */
void CreateMGraph(MGraph* G)
{
	int i, j, k, w;
	// 初始化图的顶点数和边数
	G->numNodes = 8;
	G->numEdges = 10;
	// 初始化邻接矩阵和顶点表
	for (i = 0; i < G->numNodes; i++) {
		for (j = 0; j < G->numNodes; j++) {
			G->arc[i][j] = GRAPH_INFINITY; /* 初始化邻接矩阵为∞ */
		}
		G->vexs[i] = Array[i]; /* 初始化顶点表 */
	}
	G->arc[0][0] = GRAPH_INFINITY;
	G->arc[0][1] = 10;
	G->arc[0][2] = GRAPH_INFINITY;
	G->arc[0][3] = GRAPH_INFINITY;
	G->arc[0][4] = GRAPH_INFINITY;
	G->arc[0][5] = 11;
	G->arc[0][6] = GRAPH_INFINITY;
	G->arc[0][7] = GRAPH_INFINITY;

	G->arc[1][0] = GRAPH_INFINITY;
	G->arc[1][1] = GRAPH_INFINITY;
	G->arc[1][2] = 23;
	G->arc[1][3] = GRAPH_INFINITY;
	G->arc[1][4] = GRAPH_INFINITY;
	G->arc[1][5] = GRAPH_INFINITY;
	G->arc[1][6] = 12;
	G->arc[1][7] = GRAPH_INFINITY;

	G->arc[2][0] = GRAPH_INFINITY;
	G->arc[2][1] = GRAPH_INFINITY;
	G->arc[2][2] = GRAPH_INFINITY;
	G->arc[2][3] = 21;
	G->arc[2][4] = GRAPH_INFINITY;
	G->arc[2][5] = GRAPH_INFINITY;
	G->arc[2][6] = GRAPH_INFINITY;
	G->arc[2][7] = GRAPH_INFINITY;

	G->arc[3][0] = GRAPH_INFINITY;
	G->arc[3][1] = GRAPH_INFINITY;
	G->arc[3][2] = GRAPH_INFINITY;
	G->arc[3][3] = GRAPH_INFINITY;
	G->arc[3][4] = GRAPH_INFINITY;
	G->arc[3][5] = GRAPH_INFINITY;
	G->arc[3][6] = GRAPH_INFINITY;
	G->arc[3][7] = 11;

	G->arc[4][0] = GRAPH_INFINITY;
	G->arc[4][1] = GRAPH_INFINITY;
	G->arc[4][2] = GRAPH_INFINITY;
	G->arc[4][3] = GRAPH_INFINITY;
	G->arc[4][4] = GRAPH_INFINITY;
	G->arc[4][5] = 47;
	G->arc[4][6] = GRAPH_INFINITY;
	G->arc[4][7] = 80;

	G->arc[5][0] = GRAPH_INFINITY;
	G->arc[5][1] = GRAPH_INFINITY;
	G->arc[5][2] = GRAPH_INFINITY;
	G->arc[5][3] = GRAPH_INFINITY;
	G->arc[5][4] = GRAPH_INFINITY;
	G->arc[5][5] = GRAPH_INFINITY;
	G->arc[5][6] = 6;
	G->arc[5][7] = GRAPH_INFINITY;

	G->arc[6][0] = GRAPH_INFINITY;
	G->arc[6][1] = GRAPH_INFINITY;
	G->arc[6][2] = GRAPH_INFINITY;
	G->arc[6][3] = GRAPH_INFINITY;
	G->arc[6][4] = GRAPH_INFINITY;
	G->arc[6][5] = GRAPH_INFINITY;
	G->arc[6][6] = GRAPH_INFINITY;
	G->arc[6][7] = 8;

	G->arc[7][0] = GRAPH_INFINITY;
	G->arc[7][1] = GRAPH_INFINITY;
	G->arc[7][2] = GRAPH_INFINITY;
	G->arc[7][3] = GRAPH_INFINITY;
	G->arc[7][4] = GRAPH_INFINITY;
	G->arc[7][5] = GRAPH_INFINITY;
	G->arc[7][6] = GRAPH_INFINITY;
	G->arc[7][7] = GRAPH_INFINITY;

	// 由于是无向图,邻接矩阵是对称的,需要将其对称
	for (int i = 0; i < G->numNodes; i++) {
		for (int j = 0; j < G->numNodes; j++) {
			G->arc[j][i] = G->arc[i][j];
		}
	}
	// 打印邻接矩阵
	printf("邻接矩阵为:\n");
	printf("     ");
	for (int i = 0; i < G->numNodes; i++) {
		printf("%2d ", i); /* 打印列索引 */
	}
	printf("\n     ");
	for (int i = 0; i < G->numNodes; i++) {
		printf("%2c ", G->vexs[i]); /* 打印顶点标签 */
	}
	printf("\n");
	for (int i = 0; i < G->numNodes; i++) {
		printf("%2d", i); /* 打印行索引 */
		printf("%2c ", G->vexs[i]); /* 打印顶点标签 */
		for (int j = 0; j < G->numNodes; j++) {
			if (G->arc[i][j] != 99) {
				printf("\033[31m%02d \033[0m", G->arc[i][j]); /* 打印邻接矩阵中的权值 */
			}
			else {
				printf("%02d ", G->arc[i][j]); /* 打印邻接矩阵中的权值 */
			}
		}
		printf("\n");
	}
}

//v0起点,path路径,d临时辅助最短路径数组
void Dijkstra(MGraph G, int Vstart, int TmpDistance[], int Path[]) {
	int v, w, UpcomingVex, min;
	int Visited[MAXVEX];
	//初始化所有顶点
	for (v = 0; v < G.numNodes; v++) {
		Visited[v] = FALSE;
		TmpDistance[v] = G.arc[Vstart][v];
		Path[v] = -1;
	}
	//起始点路径长度为0
	TmpDistance[Vstart] = 0;
	//起始点标记为已经被访问
	Visited[Vstart] = TRUE;
	//遍历所有顶点,总计遍历n-1次所以,主循环控制次数就从1开始,求得当前顶点Vi到达相邻结点的最近距离的顶点,并标记Visited为已经找到
	for (v = 1; v < G.numNodes; v++) {
		min = GRAPH_INFINITY; // 初始化最小距离为无穷大
		// 寻找当前未访问的顶点中距离起始点最近的顶点
		for (w = 0; w < G.numNodes; w++) {
			if (!Visited[w] && TmpDistance[w] < min) {
				UpcomingVex = w;
				min = TmpDistance[w];
			}
		}
		// 标记找到的顶点为已访问
		Visited[UpcomingVex] = true;
		// 更新从当前顶点到其他顶点的最短路径
		for (w = 0; w < G.numNodes; w++) {
			if (!Visited[w] && (min + G.arc[UpcomingVex][w] < TmpDistance[w])) {
				TmpDistance[w] = min + G.arc[UpcomingVex][w];
				Path[w] = UpcomingVex; // 记录路径
			}
		}
	}
}

// Floyd算法实现
void Floyd(MGraph G, Patharc path, ShortestPathTable table) {
	int v, w, k;
	// 初始化表和路径矩阵
	for (v = 0; v < G.numNodes; v++) {
		for (w = 0; w < G.numNodes; w++) {
			table[v][w] = G.arc[v][w];  // 初始化最短路径表
			if (G.arc[v][w] < INFINITY) {
				path[v][w] = w;  // 有直接边时,路径是目标顶点
			}
			else {
				path[v][w] = -1; // 如果没有边,则设为 -1
			}
		}
	}

	// Floyd算法的核心计算
	for (k = 0; k < G.numNodes; k++) {  // 遍历每个顶点作为中间顶点
		for (v = 0; v < G.numNodes; v++) {  // 遍历起点
			for (w = 0; w < G.numNodes; w++) {  // 遍历终点
				// 如果通过顶点 k 的路径更短,则更新路径和最短路径表
				if (table[v][w] > table[v][k] + table[k][w]) {
					table[v][w] = table[v][k] + table[k][w];
					path[v][w] = path[v][k];
				}
			}
		}
	}

	// 打印各顶点间的最短路径
	printf("\n各顶点间最短路径如下:\n");
	for (v = 0; v < G.numNodes; v++) {
		for (w = v + 1; w < G.numNodes; w++) {  // 遍历每对顶点
			//Array数组存储顶点ABCDEFGH
			printf("%c-%c weight:%d\n", Array[v], Array[w], table[v][w]);
			k = path[v][w];  // 从起点到终点的路径
			printf("path:%d", v);
			while (k != w) {  // 路径输出
				printf("->%d", k);
				k = path[k][w];
			}
			printf("->%d\n", w);
		}
		printf("\n");
	}
}

// 主函数
int main(void) {
	MGraph G;
	/* 创建图 */
	CreateMGraph(&G);  // 创建并初始化图 G
	Patharc path;
	ShortestPathTable table;
	Floyd(G, path, table);  // 计算最短路径
	return 0;
}

 无向权值图:

84ef03cba4ba478383b338ae5884012a.png

运行结果:

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

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

相关文章

swift qwen2-vl推理及加载lora使用案例

参考: https://swift.readthedocs.io/zh-cn/latest/Instruction/LLM%E5%BE%AE%E8%B0%83%E6%96%87%E6%A1%A3.html#%E5%BE%AE%E8%B0%83%E5%90%8E%E6%A8%A1%E5%9E%8B https://blog.csdn.net/weixin_42357472/article/details/142150209 SWIFT支持300+ LLM和50+ MLLM(多模态大模型…

MySQL主从同步延时高问题排查

文章目录 背景数据库性能指标1、sysbench工具安装1.1、yum方式在线安装1.2、离线安装1.3、sysbench简介 2、主从延时过高问题排查流程2.1、登录从库查看从库状态、事务及相关进程2.2、查看服务器磁盘、cpu等信息2.3、使用fio命令压测数据盘性能2.3.1、安装fio工具2.3.2、执行磁…

element-plus组件问题汇总

element-plus组件问题汇总 一、el-select 1. 下拉选项实现添加全部 问题描述&#xff1a;value为空时&#xff0c;select框中不显示全部选项&#xff0c;但是下拉列表中全部显示是勾选状态 图片&#xff1a; 解决办法&#xff1a;添加 :empty-values“[null, undefined]” …

基于Java+Mysql实现(WEB)宿舍管理系统

数据库实践课程之宿舍管理系统 一、系统需求分析 1.1 系统描述 随着社会的发展以及教育水平的提高&#xff0c;当今社会在校生的数量越来越庞大&#xff0c;使用传统的方式对学生的信息进行管理效率非常低下。在互联网技术高度发达的今天&#xff0c;使用数据库技术对学生的…

Golang | Leetcode Golang题解之第400题第N位数字

题目&#xff1a; 题解&#xff1a; func findNthDigit(n int) int {d : 1for count : 9; n > d*count; count * 10 {n - d * countd}index : n - 1start : int(math.Pow10(d - 1))num : start index/ddigitIndex : index % dreturn num / int(math.Pow10(d-digitIndex-1)…

Redis高可用,Redis性能管理

文章目录 一&#xff0c;Redis高可用&#xff0c;Redis性能管理二&#xff0c;Redis持久化1.RDB持久化1.1触发条件&#xff08;1&#xff09;手动触发&#xff08;2&#xff09;自动触发 1.2 Redis 的 RDB 持久化配置1.3 RDB执行流程(1) 判断是否有其他持久化操作在执行(2) 父进…

Unity开发一个FPS游戏之五

这个系列的前几篇文章介绍了如何从头开始用Unity开发一个FPS游戏&#xff0c;感兴趣的朋友可以回顾一下。这个系列的文章如下&#xff1a; Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个F…

828华为云征文|华为云Flexus X服务器centos挂载新增的磁盘教程

华为云Flexus X服务器推荐公司、企事业单位及生产环境使用&#xff0c;特别注重安全和稳定性 &#x1f680;【828华为云盛典&#xff0c;Flexus X引领算力新纪元&#xff01;】&#x1f680; 在数字化转型的征途中&#xff0c;数据安全是企业最坚实的后盾。华为云Flexus X实例…

中关村科金推出得助音视频鸿蒙SDK,助力金融业务系统鸿蒙化提速

鸿蒙生态大势所趋&#xff0c;各种应用适配加速 近日&#xff0c;华为纯血鸿蒙系统&#xff08;HarmonyOS NEXT&#xff09;再度引发市场高度关注。据媒体消息&#xff0c;鸿蒙NEXT Beta版将在9月24日对Mate 60系列、X5系列、Pura70系列等16款旗舰机型进行推送&#xff0c;这已…

春招审核流程优化:Spring Boot系统设计

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理大学生入学审核系统的相关信息成为必然。开…

Arcgis实现面空间位置从东至西从南至北排序

效果 背景 工作项目中经常会遇到需要对网格进行编号,而编号是有一定原则的,比如空间位置从上到下从左到右,或者其它原则,那么都可以通过下面的方式来实现 1、准备数据 点shp文件,查看初始FID字段标注,目前是一个无序的状态 2、排序 字段选择空间字段,空间排序方法…

业务流程建模(BPM)的重要性及其应用

什么是业务流程建模&#xff08;BPM&#xff09;&#xff1f; 业务流程建模&#xff08;BPM&#xff09;是对企业内各项业务流程进行图形化描述的一种方法。它旨在通过可视化的方式帮助企业理解和分析现有的业务流程&#xff0c;从而发现潜在的问题并进行改进。BPM通常采用流程…

Linux学习-Docker文件系统

Overlayfs Overlayfs 是一种类似 aufs 的一种堆叠文件系统&#xff0c;于 2014 年正式合入 Linux-3.18 主线内核&#xff0c;目前其功能已经基本稳定&#xff08;虽然还存在一些特性尚未实现&#xff09;且被逐渐推广。 Overlayfs 是一种堆叠文件系统&#xff0c;它依赖并建立…

stm32 IIC总线busy解决方法

参考博客&#xff1a; https://blog.csdn.net/PP_hui/article/details/112229696 1------这是IIC的初始化代码&#xff1a; #include "i2c.h"/* USER CODE BEGIN 0 */ // #define __HAL_AFIO_REMAP_I2C1_ENABLE() AFIO_REMAP_ENABLE(AFIO_MAPR_I2C1_REMAP) /* USE…

最新Open-vocabulary方法个人学习小结

Open-vocabulary方法总结 Yolo-world CVPR2024 预训练公式&#xff1a;区域-文本对 传统的目标检测方法&#xff0c;包括yolo系列都是用实例注释进行训练的&#xff0c;它由边界框和类别标签组成。 在本文中&#xff0c;我们将实例注释重新表述为区域-文本对。具体来说&#…

2024 年 GitLab Global DevSecOps 报告解读

近日 GitLab 正式发布了 2024 年 GitLab Global DevSecOps 报告&#xff0c;报告主题为 What’s next in DevSecOps。在全球有超 5000 位 IT 人员参与了该报告的调研&#xff0c;超 70% 为企业管理者&#xff0c;50% 以上的受访者所在企业规模超过 500人。该报告深刻揭示了在 A…

Qt进程通信,不推荐使用QSharedMemory和QLocalSocket,而是推荐ZMQ

一、据一位资深的网友说QLocalSocket有问题&#xff0c;共享内存QSharedMemory也有&#xff0c;比如存在多线程问题&#xff0c;不灵活&#xff0c;丢数据等问题都有&#xff0c;而且还占资源。血的教训。后来换成了zmqprotobuf。ZMQ进程内&#xff0c;进程间&#xff0c;机器间…

重塑科普展厅魅力,以用户体验为核心的策略性规划新探索!

如今&#xff0c;尽管数字技术已在全国范围内得到广泛应用&#xff0c;努力缩小地域间的信息鸿沟&#xff0c;但地域信息差依然是一个不容忽视的存在&#xff0c;他们由于文化背景、教育水平、生活习惯等方面的差异&#xff0c;对科普知识的需求和接受程度也各不相同&#xff0…

深入解析全连接层:PyTorch 中的 nn.Linear、nn.Parameter 及矩阵运算

文章目录 数学概念&#xff08;全连接层&#xff0c;线性层&#xff09;nn.Linear()nn.Parameter()Q1. 为什么 self.weight 的权重矩阵 shape 使用 ( out_features , in_features ) (\text{out\_features}, \text{in\_features}) (out_features,in_features)而不是 ( in_featur…

复现OpenVLA:开源的视觉-语言-动作模型及原理详解

复现OpenVLA&#xff1a;开源的视觉-语言-动作模型及原理详解 1. 摘要2. 引言3. 相关工作4. 模型结构4.1 模视觉-语言模型VLM4.2 训练流程4.3 图像分辨率4.4 微调视觉编码器4.5 训练轮数4.6 学习率4.7 训练细节4.8 参数高效微调 5. 复现5.1 下拉代码5.2 安装环境依赖5.2.1 创建…