Dijkstra算法的原理及c语言实现

源码链接: https://blog.csdn.net/qq_44394952/article/details/122587738.

1.课程设计要求

1)输入必要参数,包括:结点个数、节点间路径长度、给定节点;
2)输出给定节点到其它各节点的最短路径、径长;
3)节点间路径长度用矩阵形式表示;
4)可使用MATLAB 或者其他语言进行设计;
5)设计图形化界面展示本人的工作;

2.基本原理

1)Dijkstra算法是典型最短路径算法,用于计算单源点的最短路径问题,即求无向加权图G=<V,E,W>中一个节点到其他节点的最短路径。实际上就是根据网络的链路代价,采用广度优先搜索的思想,以起始点为中心向外层层扩展,直到扩展到终点为止来计算一对节点之间的最小代价路径。最短路径问题是图论中研究的一个重要课题,不仅仅指一般地理意义上的距离最短,还可以引申到其他的度量,如时间、费用、线路容量等。例如,城市交通中出行者选择出行路径,通信网络中的最可靠路径、最大容量路径问题等,都可以转化为最短路径问题。
2)操作步骤:
Step1:通过Dijkstra算法计算无向加权图G中的最短路径时,需要指定起点s。
Step2:引进两个集合S和U。S的作用是记录已求出最短路径的顶点以及相
应的最短路径长度,初始时被赋为 0。U记录还未求出最短路径的顶点
以及该顶点到起点s的距离,需要注意的是,U中顶点v的距离为(s,v)
的长度,如果s存在能直接到达v的边(s,v),则v的距离为(s, v);
如果s不存在能直接到达v的边(s,v),则v的距离为∞。
Step3:初始时,S中只有起点s,U中是除s之外的顶点。
Step4:从U中找出路径最短的顶点k,并将其加入到S中;接着,从U中移
除顶点k并更新U中的顶点和顶点对应的路径,之所以更新U中顶点
的距离,是由于确定了k是求出最短路径的顶点,从而可以利用k来更
新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离,则(s,v)
的距离更新为(s,k)+(k,v)的距离
Step5:重复操作步骤4),直到遍历完所有结点。
Dijkstra 每次循环都可以确定一个顶点的最短路径,故程序需要循环 n-1 次。
3)图解举例:
以下图为例,以v0为起始结点,对Dijkstra进行算法原理演示
在这里插入图片描述
在这里插入图片描述
Step1:将v0放入集合S,从v0开始,
找到与其邻接的点:v1、v2、v3,更新D(v1)、D(v2)、D(v3);
v0不与v4,v5,v6邻接,故D(v4)、D(v5)、D(v6)为∞。
在D(v)中找到最小值为1,其顶点为v1,
即此时已找到 v0到v1的最短路径为v0→v1。
Step2:将v1放入集合S,从v1开始,继续更新D(v):
v1与v2不邻接,不更新;
v1与v3不邻接,不更新;
v1与v4不邻接,不更新;
v1与v5邻接,v0→v1→v5的路径为7比D(v5)=∞小,故更新D(v5) ;
v1与v6不邻接,不更新。
在D(v)中找到最小值为2,其顶点为v2,
即此时又找到v0到v2的最短路径为v0→v2。
Step3:将v2放入集合S,从v2开始,继续更新D(v):
v2与v3不邻接,不更新;
v2与v4邻接,v0→v2→v4的路径为7比D(v4)=∞小,故更新D(v4) ;
v2与v5邻接,v0→v2→v5的路径为6比D(v5)=7小,故更新D(v5) ;
v2与v6不邻接,不更新;
在D(v)中找到最小值为3,其顶点为v3,
即此时又找到v0到v3的最短路径为v0→v3。
Step4:将v3放入集合S,从v3开始,继续更新D(v):
v3与v4邻接,v0→v3→v4的路径为7等于D(v4)=7,故不更新;
v3与v5不邻接,不更新;
v3与v6不邻接,不更新;
在D(v)中找到最小值为6,其顶点为v5,
即此时又找到v0到v5的最短路径为v0→v2→v5。
Step5:将v5放入集合S,从v5开始,继续更新D(v):
v5与v4不邻接,不更新;
v5与v6邻接,v0→v2→v5→v6的路径为14比D(v6)=∞小,故更新D(v6) ;
在D(v)中找到最小值为7,其顶点为v4,
即此时又找到v0到v4的最短路径为v0→v2→v4。
Step6:将v4放入集合S,从v4开始,继续更新D(v):
V4与v6邻接,v0→v2→v4→v6的路径为14等于D(v6)=14,故不更新;
在D(v)中找到最小值为14,其顶点为v6,
即此时又找到v0到v6的最短路径为v0→v2→v4→v6。
Step7:将v6放入集合S,所有点都已找到,停止。

3.仿真程序代码及分析

链接: https://blog.csdn.net/qq_44394952/article/details/122587738.

4.仿真结果及分析

输入结点数量、路径数量并依次输入每两个相连结点及其之间的路径长度:
在这里插入图片描述
输出结点间路径长度的矩阵
在这里插入图片描述
功能1:输入起始结点和目的结点,输出路径和距离
在这里插入图片描述
功能2:输出以v0为起始结点,其余各点为目的结点的全部路径和距离 在这里插入图片描述
通过测试发现c语言编程实现的结果与计算结果一致。
综上,通过c语言编程主要实现了两个功能:一是输入起始结点和目的结点,输出路径和距离;二是输出以v0为起始结点,其余各结点为目的结点的全部路径和距离。同时,c语言编程实现的实现因为可以输入结点数量、路径数量及每两个相连结点及其之间的路径长度,从而更具有普适性,不限制于某一给定的无向加权图。

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用C语言的优先队列库来实现dijkstra算法,例如STL中的priority_queue或者自己实现一个堆来作为优先队列。以下是使用STL中的priority_queue实现dijkstra算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <limits.h> #include <queue> #define MAXN 1000 using namespace std; typedef struct Edge { int to, w; struct Edge *next; } Edge; Edge *head[MAXN]; int dist[MAXN]; bool vis[MAXN]; void add_edge(int u, int v, int w) { Edge *e = (Edge*)malloc(sizeof(Edge)); e->to = v; e->w = w; e->next = head[u]; head[u] = e; } void dijkstra(int s, int n) { memset(dist, 0x3f, sizeof(dist)); memset(vis, false, sizeof(vis)); dist[s] = 0; priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq; pq.push(make_pair(0, s)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (vis[u]) continue; vis[u] = true; for (Edge *e = head[u]; e != NULL; e = e->next) { int v = e->to, w = e->w; if (dist[v] > dist[u] + w) { dist[v] = dist[u] + w; pq.push(make_pair(dist[v], v)); } } } } int main() { int n, m, s; scanf("%d%d%d", &n, &m, &s); for (int i = 1; i <= m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); add_edge(u, v, w); } dijkstra(s, n); for (int i = 1; i <= n; i++) { printf("%d ", dist[i]); } printf("\n"); return 0; } ``` 这个代码实现了使用优先队列实现dijkstra算法,其中priority_queue是STL中的优先队列,用于存储节点到源点的距离和节点编号的pair,按照距离从小到大排序。在每次取出队首元素时,如果该节点已经被访问过,则跳过,否则将其标记为已访问,并遍历其所有出边,更新到其它节点的距离。如果某个节点的距离被更新,则将其加入优先队列中,以便下一次取出时能够得到最小的距离。最终输出源点到所有节点的最短距离。 lua closure factory 完整代码: ```lua function new_counter() local count = 0 return function() count = count + 1 return count end end local counter1 = new_counter() local counter2 = new_counter() print(counter1()) -- 1 print(counter1()) -- 2 print(counter2()) -- 1 print(counter2()) -- 2 ``` 这段代码实现了一个闭包工厂,用于创建计数器函数。每次调用new_counter函数都会返回一个新的计数器函数,该函数内部维护一个计数器变量count,并在每次调用时将其加1并返回。由于每个计数器函数都有自己的count变量,因此可以实现多个计数器同时存在而不会互相干扰。在示例代码中,创建了两个计数器counter1和counter2,并分别调用它们两次,输出结果为1、2、1、2。 中文加密: 中文加密是指将中文文本转换为一串密文,以保护文本的机密性。常见的中文加密算法包括DES、AES、RSA等。其中DES是一种对称加密算法,AES和RSA是一种非对称加密算法。 对称加密算法指加密和解密使用相同的密钥,因此密钥的安全性非常重要。DES算法使用56位的密钥,将明文分成64位的块,经过16轮加密后得到密文。AES算法使用128位、192位或256位的密钥,将明文分成128位的块,经过多轮加密后得到密文。对称加密算法的优点是加密速度快,缺点是密钥的管理比较困难。 非对称加密算法指加密和解密使用不同的密钥,其中一个密钥称为公钥,另一个密钥称为私钥。RSA算法使用两个大素数作为私钥,将其乘积作为公钥,将明文转换为一个整数后进行加密,得到密文后再用私钥解密。非对称加密算法的优点是密钥管理方便,缺点是加密速度慢。 中文加密算法的选择应该根据具体的需求和场景来决定,需要综合考虑加密强度、加密速度、密钥管理等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值