数据结构 -最短路径dijkstra(迪杰斯特拉)算法讲解及代码实现

news2024/12/28 22:12:16

        迪杰斯特拉算法是一种广义的贪心算法,求出局部最优解,再去求全局最优解

图文讲解:

举例图:(起始点为1)

辅助数组:

s:记录了目标顶点到其他顶点的最短路径是否求得(求得为1,否则为0)

p:目标顶点到其他顶点的最短路径的前驱节点

(如,求得1->7->5的最短路径,那么5的前驱节点为7)

d:记录目标顶点到其他顶点最短距路径的长度 

首先利用二维数组构建图中各个顶点的辅助数组的初始化关系:

初始化的解析:初始化只知道目标顶点:顶点1到自己的最短路径也就是0,所以s1为1其余没有求得标记为0,p中目标顶点v1到1 3 4 5顶点都没有弧也就是没有目标顶点到此节点的前驱节点设为-1,

d为目标顶点v1到与他有弧的节点的弧长度(权重),没有弧的则设置为无穷(32767) 

 步骤:(x集合为记录已经找到最短路径的节点,最初x:v1(目标节点))

1.每次从d中找到最小的数,并找到其节点下标,将此节点的s标记为1意味已找到目标节点到此节点的最短路径,再把此节点加入到我们的x集合当中。

2.把已经找到的最小路径的节点当作中专点,判断目标顶点到当前节点的路径+当前节点到其他节点的路径是都小于目标节点到其他节点的路径长度,如过小于则更新目标节点的长度。

(如v1-v3为无穷,v1-v2-v3为22,小于无穷所以把v1-v3的路径改为22:d2为22)

3.重复1,2的操作直到x集合标记完所有节点(s数组元素全部为1)。

代码实现:

#include <stdio.h>
#include <stdlib.h>
#define MAX 32767
typedef struct Graph
{
	char* vexs;//顶点
	int** arcs;//边(用二级指针存放存放边的一级指针,一级指针存放边)
	int vexsNum;//顶点的个数
	int arcsNum;//边的个数
}Graph;

Graph* initGraph(int vexNum)
{
	Graph* G = (Graph*)malloc(sizeof(Graph));
	G->vexs = (char*)malloc(sizeof(char)*vexNum);
	G->arcs = (int**)malloc(sizeof(int*)*vexNum);
	for (int i = 0; i < vexNum; i++)
	{
		G->arcs[i] = (int*)malloc(sizeof(int) * vexNum);
	}
	G->vexsNum = vexNum;
	G->arcsNum = 0;
	return G;
}

void crativeGraph(Graph* G, char* vexs, int* arcs)
{
	for (int i = 0; i <G->vexsNum; i++)
	{
		G->vexs[i] = vexs[i];//(Graph中的顶点数组存放顶点的“名字”)
	for (int j = 0; j < G->vexsNum; j++)
		{
			G->arcs[i][j] = *(arcs + i * G->vexsNum + j);//二维数组加一个数表示第i+1个元素(相当于把二维数组全排成一行)                                                            
			if (G->arcs[i][j] > 0 && G->arcs[i][j] != MAX)
				G->arcsNum++;//统计边的个数(二维数组中有边则元素为1) //这里的图为带权重的图所以再统计边的时候二维数组元素既要大于0也要不为无穷                                                                  
		}
	}
	G->arcsNum /= 2;//(二维数组计算了两次边的次数)
}
//DFS深度优先遍历的访问
void DFS(Graph* G, int* visited, int index)
{
	if (index==4)
	{
		printf("%c ", G->vexs[index]);
		visited[index] = 1;
	}
	else
	{
		printf("%c->", G->vexs[index]);//先打印出顶点
		visited[index] = 1;//再把访问过的顶点做标记
	}
	for (int i = 0; i < G->vexsNum; i++)
	{
		if (G->arcs[index][i] > 0 && G->arcs[index][i] != MAX && !visited[i])//因为为带权重的图所以dfs访问的时候边的条件也是要满足>0且!=无穷两节点才有边
		{
			DFS(G, visited, i);
		}
	}
}
void dijkstra(Graph* G,int index)
{//准备辅助数组
	int* s = (int*)malloc(sizeof(int) * G->vexsNum);//记录最短路径是否求得(1是,0否)
	int* p = (int*)malloc(sizeof(int) * G->vexsNum);//记录目标顶点到其他顶点的最短路径的前驱节点
	int* d = (int*)malloc(sizeof(int) * G->vexsNum);//记录了目标顶点到其他顶点的最短路径长度
	//初始化辅助数组
	for (int i = 0; i < G->vexsNum; i++)
	{//最初我们只知道目标顶点到自己的最短路径
		if (i == index)
			s[i] = 1;
		else
			s[i] = 0;
	}
	for (int i = 0; i < G->vexsNum; i++)
	{
		if (G->arcs[index][i] > 0 && G->arcs[index][i] != MAX)
			p[i] = index;//如果节点与目标节点有弧则将此节点的前驱节点设为目标节点

		else
			p[i] = -1;
	}
	for (int i = 0; i < G->vexsNum; i++)
	{
		if (G->arcs[index][i] > 0 && G->arcs[index][i] != MAX)
			d[i] = G->arcs[index][i];
		else
			d[i] = MAX;
		if (i == index)
			d[i] = 0;
	}
	printf("最初图 的辅助数组\n");
	for (int i = 0; i < G->vexsNum; i++)
	{
		printf("%d %d %d\n", s[i],p[i],d[i]);//三个数组是竖着输出的
	}
	
	for (int i = 0; i < G->vexsNum - 1; i++)
	{
		int index = getMin(d,s,G);
		s[index] = 1;//将s数组数组元素改为1意味着:已经找到起始节点到此节点的最短路径
		for (int j = 0; j < G->vexsNum; j++)
		{//将返回的节点作为中转点
			if (!s[j] && d[index] + G->arcs[index][j] < d[j])//判断v1到中专点的距离+到其他节点的距离和是否小于v1到其他节点的距离
			{
				d[j] = d[index] + G->arcs[index][j];//如果小于则更新v1-此节点的最短路径
				p[j] = index;//并且将此节点的前驱节点改为中转点
			}
		}
	}
	printf("最短路径的图的辅助数组\n");
	for (int i = 0; i < G->vexsNum; i++)
	{
		printf("%d %d %d\n", s[i], p[i], d[i]);
	}
}
int getMin(int* d, int* s, Graph* G)
{
	int min = MAX;
	int index = 0;
	//找与起始节点有弧的且弧长度最小(权重最短)的节点,并且返回此节点的下标
	for (int i = 0; i < G->vexsNum; i++)
	{
		if (!s[i] && d[i] < min)
		{
			min = d[i];
			index = i;
		}
	}
	return index;
}
int main()
{
	Graph* G = initGraph(7);
	//创建深度优先遍历的时候判断该顶点是否被访问的数组
	int* visited = (int*)malloc(sizeof(int) * G->vexsNum);
	for (int i = 0; i < G->vexsNum; i++)
	{
		visited[i] = 0;//先把每个元素都设为0,当被访问过的时候就改变元素的值
	}
	//提前根据图的数创建出符合其边的关系的二位数组
	int arcs[7][7] =
	{
		0,12,MAX,MAX,MAX,16,14,
		12,0,10,MAX,MAX,7,MAX,
		MAX,10,0,3,5,6,MAX,
		MAX,MAX,3,0,4,MAX,MAX,
		MAX,MAX,5,4,0,2,8,
		16,7,6,MAX,2,0,9,
		14,MAX,MAX,MAX,8,9,0
	};
	crativeGraph(G, "1234567", (int*)arcs);//节点的“名字”
	DFS(G, visited, 0);//这里我们把目标节点定位v1所以index传0
	dijkstra(G, 0);
	printf("\n");
	return 0;
}

“不看广告看疗效”

(辅助数组我们都是竖着输出的)

最后我们可以通过辅助数组找到目标节点到任何节点的最短路径

eg:目标节点-v5

1.先找v5的前驱节点v6,路径为18

2.找v6的前驱节点为v1,路径为16

所以v1-v5的路径为v1-v6-v5,最短路径为18+16=34. 

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

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

相关文章

代码调试技巧

目录 1.为什么要进行调试&#xff1f; 2.调试的基本步骤 3.关于Debug版本和Release版本 4.调试技巧 5.调试总结 我还是喜欢真实的世界&#xff0c;因为在那里&#xff0c;我可以通过自己的努力来改变残酷的现实 本专栏适用于有一定C语言基础并且还要继续学习的人 往期…

CryoEM - 冷冻电镜 CryoSPARC 软件的安装与环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/130809095 CryoSPARC 软件是一种用于冷冻电镜数据处理的创新工具&#xff0c;可以快速、准确地重建生物分子的三维结构。CryoSPARC 软件…

【使用ChatGPT制作PPT】

内容目录 一、利用ChatGPT生成PPT内容1. 打开ChatGPT&#xff1a;2. 输入需求&#xff1a;3. 复制&#xff1a; 二、制作生成PPT1. 打开PPT制作网站&#xff1a;2. 左侧网页版-导入创建-粘贴Markdown内容-导入创建3. 自行更改副标题、演讲者、选择模板、演示及下载 一、利用Cha…

Linux网络——shell编程之iptables防火墙

Linux网络——shell编程之iptables防火墙 一、概述1.iptables2.netfilter 和 iptables的关系 二、iptables中的四表五链1.四表五链的关系2.四表3.五链 三、匹配顺序1.数据包到达防火墙的匹配流程2.规则链之间的匹配顺序3.规则链内的匹配顺序 四、iptables 防火墙的配置方法1.ip…

python tesseract-ocr + jTessBoxEditorFX 训练自定义字库

在使用tesseract-ocr进行字符识别时&#xff0c;我们使用了官方提供的字库&#xff0c;例如英文字库、中文字库&#xff0c;但这些字库并不一定能满足我们所有的需求。所以有些时候&#xff0c;我们就需要训练属于自己的自定义字库。废话少说&#xff0c;直接开干。 第一步&am…

联想首次展示全栈算力方案服务,品牌换新亮相

1、联想算力&#xff0c;第一次真正被所有人感知。 2、基于软硬服一体化的优势&#xff0c;联想打造了丰富多样的四维算力服务&#xff0c;即融合化、场景化、订阅化、绿色化&#xff0c;可以满足不同企业、不同行业的定制化需求。 5月20日&#xff0c;主题为“联想方案服务&am…

2023中兴软件类笔试

1.下列Python代码&#xff1a;将近似输出什么&#xff1f; import numpy as np print np.sqrt(6*np.sum(1/np.arange(1,1000000, dtypenp.float)**2))这段代码是用来计算圆周率的巴塞尔问题&#xff08;Basel problem&#xff09;的近似值&#xff0c;输出结果将近似为3.14159…

使用SMTP协议发送邮件

剧情介绍 今天心血来潮&#xff0c;学了一下Python3&#xff0c;里面有个章节是发送邮件&#xff0c;用示例里面的代码&#xff0c;运行后报错&#xff0c;然后记录一下问题是如何解决的&#xff0c;大家可以看一下&#xff0c;可以有效避坑。 SMTP协议介绍 SMTP&#xff08…

Mysql数据库备份 一天一次 保存最新五天 每天凌晨三点备份

Mysql数据库备份 一天一次 保存最新五天 每天凌晨一点三十备份 步骤一 先查看 sudo systemctl status crond 是否存在 不存在执行下面代码 sudo yum install cronie sudo systemctl start crond sudo systemctl enable crond sudo systemctl status crond 步骤二 Cd /home …

从零开始 Spring Boot 33:Null-safety

从零开始 Spring Boot 33&#xff1a;Null-safety 图源&#xff1a;简书 (jianshu.com) Null-safety&#xff08;null安全&#xff09;实际上是Java这个“古老”语言的历史包袱&#xff0c;很多新的语言&#xff08;比如go或kotlin&#xff09;在诞生起就在语言层面提供对null…

软件测试需要学习什么?好学吗?需要学多久?到底是报班好还是自学好?

目录 前言&#xff1a; 【文章的末尾给大家留下了大量的福利哦。】 一&#xff1a;软件测试好学吗&#xff1f;需要学习多久&#xff1f; 二&#xff1a;那么选择软件测试行业有什么优势呢&#xff1f; 三&#xff1a;再来说说大家最关心的——软件测试人员的薪资怎么样? …

Spring : XML配置 JavaBean

文章目录 前言一、xml 加载 Bean 对象总结XML加载Bean对象 前言 跟着大佬走&#xff01;&#xff01;&#xff01;&#xff01; https://github.com/DerekYRC/mini-spring 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、xml 加载 Bean 对象 大家先…

【C语言】数组名作函数参数

数组名作函数参数 引例思考例2通用性指针形参和数组形参几点说明 引例 在主函数中输入10个整数&#xff0c;并存入一个一维数组中&#xff1b;然后在被调函数中&#xff0c;将0号元素的值改为原值的10倍&#xff1b;最后在主函数中输出结果。 思路&#xff1a; 若想在被调函数…

10:00进去,10:05就出来了,这问的也太变态了···

从外包出来&#xff0c;没想到死在另一家厂子了。 自从加入这家公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到5月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资直降30%&#xff0c;顿时有吃不起饭的赶脚。 好在有个兄弟内推…

SSM框架-SpringMVC

1. SpringMVC 1.1 Spring与Web环境集成 ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的&#xff0c;但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(spring配置文件) &…

ActiveMq消息队列

ActiveMq是一种开源的java程序&#xff0c;支持Java消息服务(JMS) 1.1 版本 一、持久化机制 1、KahaDB&#xff1a;5.4及之后版本&#xff0c;默认使用日志文件 activemq.xml默认使用KahaDB持久化存储&#xff0c;默认配置安装路径data目录下 <persistenceAdapter> …

Django框架之模板其他补充

本篇文章是对django框架模板内容的一些补充。包含注释、html转义和csrf内容。 目录 注释 单行注释 多行注释 HTML转义 Escape Safe Autoescape CSRF 防止csrf方式 表单中使用 ajax请求添加 注释 单行注释 语法&#xff1a;{# 注释内容 #} 示例&#xff1a; {# 注…

09 FPGA—利用状态机实现可乐售卖机(附代码)

1. 理论 FPGA 是并行执行的&#xff0c;如果我们想要处理具有前后顺序的事件&#xff0c;就需要引入状态机。举个例子&#xff0c;将人看成 FPGA ,我们可以在散步的时候听歌和聊天这是并行执行的&#xff0c;但一天的行程安排却是以时间段前后执行的。 状态机简写为 FSM&#…

java前后端分离有详细内容吗?

微服务架构java前后端分离都有哪些具体内容&#xff1f;目前&#xff0c;有不少客户朋友经常询问我们类似的问题。其实&#xff0c;在新的经济发展形势下&#xff0c;提质增效的低代码开发平台微服务架构早已成为不少新老客户的选择&#xff0c;它们不仅能提高办公协作效率&…

成为更优秀的项目经理:快速提升影响力的六大原则与独门秘笈

在很多公司的组织架构中&#xff0c;项目经理并不是一个常规的职能岗位&#xff0c;项目组是为了某个项目目标临时组建的团队&#xff01; 这就造成了PM一个很尴尬的处境&#xff0c;权、责、利不匹配&#xff0c;也就是有责无权&#xff1a;PM既要对项目目标的实现负责&#…