C语言 最短路径 迪杰斯特拉(Dijkstra)算法

前言

迪杰斯特拉(Dijkstra)算法是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中单源最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。


不太懂的可以看视频 QWQ  (来着@Abel)

Dijkstra算法讲解


算法实现:

  1. 定义一个数组dist[],dist[i]表示从起点到顶点i的最短路径长度,初始化为无穷大,dist[s]=0,其中s为起点。
  2. 定义一个数组visited[],visited[i]表示顶点i是否已经被标记为已确定最短路径的顶点,初始化为false。
  3. 从dist[]中找到当前未被标记的dist[i]最小的顶点u,标记visited[u]=true。
  4. 遍历所有与u相邻的顶点v,如果visited[v]=false,且从起点到u再到v的路径长度小于dist[v],则更新dist[v]=dist[u]+w(u,v),其中w(u,v)为边(u,v)的权值。

重复步骤3和步骤4,直到所有顶点都被标记为已确定最短路径的顶点。

迪杰斯特拉(Dijkstra)算法_小C哈哈哈的博客-CSDN博客_迪杰斯特拉算法

以下是求无向网(储存方式为邻接矩阵)中起点s到各点的最短路径的代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdbool.h>
#include <malloc.h>
#define MVNum 100//最大顶点数
#define MaxInt 66666//表示极大值
typedef struct {
	char vexs[MVNum];//顶点表(顶点为字符型)
	int arcs[MVNum][MVNum];//邻接矩阵(权值为整型)
	int vexnum, arcnum;//图的当前点数和边数
}AMGraph;

//定位
int LocateVex(AMGraph* G, char v) {
	int i;
	for (i = 0; i < G->vexnum; i++) {
		if (G->vexs[i] == v) {
			return i;
		}
	}
	return -1;
}

//无向网的建立
AMGraph* CreateUDN() {
	int i, j, k, w;
	char v1, v2;
	AMGraph* G = malloc(sizeof(AMGraph));
	printf("输入总顶点数,边数\n");
	scanf("%d%d", &G->vexnum, &G->arcnum);
	getchar();//吸收换行符
	printf("依次输入点的信息\n");
	for (i = 0; i < G->vexnum; i++) {
		scanf("%c", &G->vexs[i]);
	}
	getchar();//吸收换行符
	for (i = 0; i < G->vexnum; i++)
		for (j = 0; j < G->vexnum; j++) {
			if (i == j) {
				G->arcs[i][j] = 0;
			}
			else {
				G->arcs[i][j] = MaxInt;
			}
		}
	for (k = 0; k < G->arcnum; k++) {
		printf("输入一条边依附的顶点及权值\n");
		scanf("%c%c", &v1, &v2);
		scanf("%d", &w);
		getchar();//吸收换行符
		i = LocateVex(G, v1), j = LocateVex(G, v2);//确定v1、v2在顶点数组的下标
		G->arcs[i][j] = w;//边<v1,v2>权值置为w
		G->arcs[j][i] = w;//无向网对称边<v2,v2>权值也置为w
	}
	return G;
}

//输出邻接矩阵
void print(AMGraph* G) {
	int i, j;
	printf("  ");
	for (i = 0; i < G->vexnum; i++) {
		printf("%c ", G->vexs[i]);
	}
	printf("\n");
	for (i = 0; i < G->vexnum; i++) {
		printf("%c ", G->vexs[i]);
		for (j = 0; j < G->vexnum; j++) {
			if (G->arcs[i][j] == MaxInt)
				printf("∞ ");
			else
				printf("%d ", G->arcs[i][j]);
		}
		printf("\n");
	}
}

//迪杰斯特拉算法
void Dijkstra(AMGraph* G, int s) {
	int dist[MVNum];//用来储存各顶点与起点的距离
	bool visited[MVNum];//用来标记已确定最短路径的顶点
	int i, j, k, u, min;
	//初始化数组dist与visited
	for (i = 0; i < G->vexnum; i++) {
		dist[i] = MaxInt;
		visited[i] = false;
	}
	dist[s] = 0;//起始点s最短距离为0
	//每次循环会标记一个顶点u,直到所有顶点被标记(循环次数就是顶点数-1,起点已找到最短路径0)
	for (k = 1; k < G->vexnum; k++) {
		min = MaxInt;
		//找到当前未被标记的距离起点最近的顶点u
		for (i = 0; i < G->vexnum; i++) {
			if (dist[i] < min && !visited[i]) {
				u = i;
				min = dist[i];
			}
		}
		visited[u] = true;//标记顶点u
		/*遍历顶点u的邻结点,当 dist[u] + G->arcs[u][j] < dist[j]时
		(顶点u距离起点s的长度dist[u]加上顶点u与邻接点j的距离G->arcs[u][j]小于顶点j距离起点s的距离dist[j]),
		更新顶点j距离起点的路径长度*/
		for (j = 0; j < G->vexnum; j++) {
			if (!visited[j] && dist[u] + G->arcs[u][j] < dist[j]) {
				dist[j] = dist[u] + G->arcs[u][j];
			}
		}
	}
	//输出结果
	for (i = 0; i < G->vexnum; i++) {
		printf("起点%c到顶点%c的最短路径为:%d\n", G->vexs[s], G->vexs[i], dist[i]);
	}
}

int main() {
	AMGraph* G = CreateUDN();
	printf("该无向网邻接矩阵为:\n");
	print(G);
	Dijkstra(G, 0);
}

若顶点数为n,求解最短路径的主循环共进行n-1次,每次执行的时间为O\left ( n \right ),所以算法时间复杂度为O\left ( n^{2} \right )


示例:

求如下图所示v0到各点的最短路径

 运行结果如下:

A、B、C······代替v0、v1、v2······


总结

如果是有向网或者是以邻接表方式储存的有权图,算法实现流程还是一样的,只不过代码上大同小异。

  • 12
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
迪杰斯特拉算法是一种用于求解带权图中单源最短路径问题的贪心算法。它的基本思想是从源点开始,依次确定各个顶点到源点的最短路径长度,直到求出源点到图中所有其他顶点的最短路径。 具体来说,迪杰斯特拉算法的实现步骤如下: 1. 初始化:将源点的最短路径长度设置为0,将所有其他顶点的最短路径长度设置为无穷大。 2. 选择顶点:从所有未确定最短路径的顶点中选择一个距离源点最近的顶点,将其标记为确定最短路径。 3. 更新:对于与选定顶点相邻的所有未确定最短路径的顶点,根据选定顶点到源点的距离以及选定顶点到这些顶点的距离,更新它们的最短路径长度。 4. 重复以上步骤,直到所有顶点的最短路径长度都被确定。 以下是一个简单的C语言实现: ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define MAX_VERTICES 100 #define INFINITE 1000000 int graph[MAX_VERTICES][MAX_VERTICES]; int dist[MAX_VERTICES]; bool visited[MAX_VERTICES]; int num_vertices; void dijkstra(int start) { // 初始化 for (int i = 0; i < num_vertices; i++) { dist[i] = INFINITE; visited[i] = false; } dist[start] = 0; // 选择顶点 for (int i = 0; i < num_vertices - 1; i++) { int min_dist = INFINITE; int min_vertex = -1; for (int j = 0; j < num_vertices; j++) { if (!visited[j] && dist[j] < min_dist) { min_dist = dist[j]; min_vertex = j; } } visited[min_vertex] = true; // 更新 for (int k = 0; k < num_vertices; k++) { if (!visited[k] && graph[min_vertex][k] != 0 && dist[k] > dist[min_vertex] + graph[min_vertex][k]) { dist[k] = dist[min_vertex] + graph[min_vertex][k]; } } } } int main() { // 读入图 scanf("%d", &num_vertices); for (int i = 0; i < num_vertices; i++) { for (int j = 0; j < num_vertices; j++) { scanf("%d", &graph[i][j]); } } // 运行算法 dijkstra(0); // 输出结果 for (int i = 0; i < num_vertices; i++) { printf("%d ", dist[i]); } printf("\n"); return 0; } ``` 在这个实现中,`graph`数组表示输入的带权图,`dist`数组表示每个顶点到源点的最短路径长度,`visited`数组表示每个顶点是否已经确定最短路径算法的核心部分在`dijkstra`函数中实现,其中使用两个嵌套的循环分别进行顶点的选择和路径长度的更新。最终结果输出在`dist`数组中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Indifferent-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值