Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径
一、文章说明:
- C++语言实现;
- 有向图的存储结构为: 邻接矩阵;
- 这篇文章的代码是我根据B站UP主懒猫老师所写的,能成功运行,VS里面显示有很多警告。而且还可能存在有未调试出的BUG,请多多指教。
- 观看懒猫老师的视频后,才方便理解博主代码,不然可能理解起来会很吃力。
二、 算法思想与实现思路:
请前往B站观看 up主 懒猫老师 的教学视频;
——附:老师思路清楚,并且通过形象的PPT动画来模拟算法实现过程,非常有利于理解整个算法过程!
视频链接:
1.算法思想:
懒猫老师-数据结构-(46)最短路径(Dijkstra算法,迪杰斯特拉算法,单源最短路径)
2.算法实现过程:
懒猫老师-数据结构-(47)最短路径(Dijkstra算法实现,迪杰斯特拉算法,单源最短路径)
三、3个核心函数:
1.迪杰斯特拉算法函数;
void Dijkstra(AMGraph g)
{int start;char c;cout << "请输入最小路径的源点:" << "\t";cin >> c; start = g.Locate_vex(c); //利用定位函数查找源点在顶点表当中的序号;//1.用动态分配的方式,为路径path, 路径权值dist, 算法思想中的S数组开辟空间。//注意这里path,dist,S数组单元的序号所对应的顶点和类 AMGraph中顶点表 vexs 所对应的顶点是一样的!int* path = new int[g.vexnum]; //空间大小为 图的顶点个数,vexnum;int* dist = new int[g.vexnum];int* S = new int[g.vexnum];//2. 初始化这三个数组;for (int i = 0; i < g.vexnum; i++){dist[i] = g.arcs[start][i];if (dist[i] != Maxlnt) path[i] = start;else path[i] = -1;}for (int i = 0; i < g.vexnum; i++){S[i] = 0; // 0代表未进入算法思想的S集合,1代表已经进入。}S[start] = 1; // 将源点加入S集合。int num = 1; //计数变量,循环控制条件;int min;//3. 正式进入算法,求源点到其它顶点的最短路径。while (num < g.vexnum){min = findMinDist(dist, S, g.vexnum); //查找在当前顶点所邻接后继结点的边中,具有最小权值的后继结点的序号。S[min] = 1;for (int i = 0; i < g.vexnum; i++) //对路径数组path 和路径权值数组dist 进行更新。{if ((S[i] == 0) && (dist[i] > dist[min] + g.arcs[min][i])){dist[i] = dist[min] + g.arcs[min][i];path[i] = min;}}num++;}displayPath(dist, path, start, g);delete[]path;delete[]dist;delete[]S;
}
2.findMinDist()函数;
函数功能:
查找当前结点与后继邻接顶点中具有最小权值的边,的邻接顶点的序号
int findMinDist(int dist[], int S[], int n)
{int MIN = Maxlnt + 1;int mark = -1;for (int i = 0; i < n; i++){if (S[i] == 0){if (dist[i] < MIN){MIN = dist[i];mark = i;}}}return mark;
}
3. 路径输出函数displayPath();
函数功能:
- 一、如果对于除了源点的其它顶点,如果源点是可达该顶点的,则输出其的最小路径和权值
- 二、输出源点所到达不了的顶点,说明这源点和这个顶点之间不存在有最短路径。
void displayPath(int dist[], int path[], int start, AMGraph g)
{char* road = new char[g.vexnum];int number; //number 用来表示源点到第i号顶点路径的长度;for (int i = 0; i < g.vexnum; i++){int j = i; //这里j可以从充当一个指针,一开始指向每条路径的终点。if (j != start && dist[j] != Maxlnt) //注意这里j指向的终点必须是可达源点的,所以要加上判断条件 dist[j] 不可以等于无穷大 Maxlnt ;{number = -1;//1.利用while循环,从最短路径的终点向源点逐步衍生,逐步扩大road数组while (g.vexs[j] != g.vexs[start]) //当j 指向源点的时候,循环结束。{number++;road[number] = g.vexs[j];j = path[j]; //j指向当前顶点的,前驱邻接顶点。if (j == start) //如果 j 指向源点了,将源点加入road 数组,数组中存储的就是逆序的路径了,number为路径的长度。{number++;road[number] = g.vexs[j];}}//2.利用for循环,将路径数组逆序输出即可得到 源点到第 i 号顶点的最小路径。cout << endl << g.vexs[start] << " to " << g.vexs[i] << " " << "路径权值:" << dist[i] << "\t" << "路径为: ";for (int k = number; k >= 0; k--){if (k == 0){cout << road[k] << endl;}else cout << road[k] << "—>";}cout << endl;}}//3.布尔变量adjust, 用来判断源点是否有到达不了的顶点, 如果有则利用for循环输出。bool adjust = true;for (int i = 0; i < g.vexnum; i++){if (dist[i] == Maxlnt){adjust = false;break;}}if (adjust == false){cout << endl << "源点:" << g.vexs[start] << "到达不了的顶点为:" << "\t";for (int i = 0; i < g.vexnum; i++){if (dist[i] == Maxlnt)cout << g.vexs[i] << "\t";}cout << endl << endl;}delete[]road;
}
四、完整代码:
说明: 为了更方便地调试程序,我将算法具体实现写成了一个小小系统的形式,
所以代码会比较冗长,注释也比较多,阅读起来可能很不舒适。
#include<iostream>
#include<string>
using namespace std;#define Maxlnt 32767
#define MVNum 20
#define OK 1class AMGraph
{private:char vexs[MVNum]; //顶点表;int arcs[MVNum][MVNum]; //边表;int vexnum, arcnum; //点的数量和边的数量;
public:bool creat_graph();int Locate_vex(char c); //顶点定位函数,定位顶点在顶点表当中的数字;void print(); // 图的信息打印函数;friend void displayPath(int dist[], int path[], int start, AMGraph g); // 路径输出函数;friend void Dijkstra(AMGraph g);};int AMGraph::Locate_vex(char c)
{for (int i = 0; i < vexnum; i++){if (c == vexs[i]) return i;}return -1;
}bool AMGraph::creat_graph()
{cout << "请依次输入图的顶点数目和边数:" << "\t";cin >> vexnum >> arcnum;cout << endl << "请依次输入" << vexnum << "个顶点:" << "\t";for (int i = 0; i < vexnum; i++){cin >> vexs[i];}for (int i = 0; i < vexnum; i++){for (int j = 0; j < vexnum; j++){if (i == j) arcs[i][j] = 0;else arcs[i][j] = Maxlnt;}}cout << endl;for (int k = 0; k < arcnum; k++){char v1, v2;int w;cout << "请分别输入第" << k + 1 << "条有向边的起点,终点和权值:" << "\t";cin >> v1 >> v2 >> w;int i = Locate_vex(v1);int j = Locate_vex(v2);arcs[i][j] = w;}return OK;
}void AMGraph::print()
{cout << endl << "顶点表的信息:" << endl;for (int i = 0; i < vexnum; i++){cout << vexs[i] << " ";}cout << endl << endl;cout << "邻接矩阵的信息为:" << endl;// 这里for循环 从-1 开始打印邻接矩阵表格;for (int i = -1; i < vexnum; i++){for (int j = -1; j < vexnum; j++){//i=-1的时候, 需要输出边表中, 以i为起点的边所对应的终点;if (i == -1){if (j == -1)cout << " " << "\t";else cout << vexs[j] << "\t";if (j == vexnum - 1) //换行条件控制cout << endl;}else{//j=-1的时候,需要输出边表中, 以j为终点的边所对应的起点: if (j == -1)cout << vexs[i] << "\t";else{if (arcs[i][j] == Maxlnt)cout << "∞" << "\t";else cout << arcs[i][j] << "\t";if (j == vexnum - 1) //换行条件控制cout << endl;}}}}
}int findMinDist(int dist[], int S[], int n)
{int MIN = Maxlnt + 1;int mark = -1;for (int i = 0; i < n; i++){if (S[i] == 0){if (dist[i] < MIN){MIN = dist[i];mark = i;}}}return mark;
}void displayPath(int dist[], int path[], int start, AMGraph g)
{char* road = new char[g.vexnum];int number; //number 用来表示源点到第i号顶点路径的长度;for (int i = 0; i < g.vexnum; i++){int j = i; //这里j可以从充当一个指针,一开始指向每条路径的终点。if (j != start && dist[j] != Maxlnt) //注意这里j指向的终点必须是可达源点的,所以要加上判断条件 dist[j] 不可以等于无穷大 Maxlnt ;{number = -1;//1.利用while循环,从最短路径的终点向源点逐步衍生,逐步扩大road数组while (g.vexs[j] != g.vexs[start]) //当j 指向源点的时候,循环结束。{number++;road[number] = g.vexs[j];j = path[j]; //j指向当前顶点的,前驱邻接顶点。if (j == start) //如果 j 指向源点了,将源点加入road 数组,数组中存储的就是逆序的路径了,number为路径的长度。{number++;road[number] = g.vexs[j];}}//2.利用for循环,将路径数组逆序输出即可得到 源点到第 i 号顶点的最小路径。cout << endl << g.vexs[start] << " to " << g.vexs[i] << " " << "路径权值:" << dist[i] << "\t" << "路径为: ";for (int k = number; k >= 0; k--){if (k == 0){cout << road[k] << endl;}else cout << road[k] << "—>";}cout << endl;}}//3.布尔变量adjust, 用来判断源点是否有到达不了的顶点, 如果有则利用for循环输出。bool adjust = true;for (int i = 0; i < g.vexnum; i++){if (dist[i] == Maxlnt){adjust = false;break;}}if (adjust == false){cout << endl << "源点:" << g.vexs[start] << "到达不了的顶点为:" << "\t";for (int i = 0; i < g.vexnum; i++){if (dist[i] == Maxlnt)cout << g.vexs[i] << "\t";}cout << endl << endl;}delete[]road;
}void Dijkstra(AMGraph g)
{int start;char c;cout << "请输入最小路径的源点:" << "\t";cin >> c; start = g.Locate_vex(c); //利用定位函数查找源点在顶点表当中的序号;//1.用动态分配的方式,为路径path, 路径权值dist, 算法思想中的S数组开辟空间。//注意这里path,dist,S数组单元的序号所对应的顶点和类 AMGraph中顶点表 vexs 所对应的顶点是一样的!int* path = new int[g.vexnum]; //空间大小为 图的顶点个数,vexnum;int* dist = new int[g.vexnum];int* S = new int[g.vexnum];//2. 初始化这三个数组;for (int i = 0; i < g.vexnum; i++){dist[i] = g.arcs[start][i];if (dist[i] != Maxlnt) path[i] = start;else path[i] = -1;}for (int i = 0; i < g.vexnum; i++){S[i] = 0; // 0代表未进入算法思想的S集合,1代表已经进入。}S[start] = 1; // 将源点加入S集合。int num = 1; //计数变量,循环控制条件;int min;//3. 正式进入算法,求源点到其它顶点的最短路径。while (num < g.vexnum){min = findMinDist(dist, S, g.vexnum); //查找在当前顶点所邻接后继结点的边中,具有最小权值的后继结点的序号。S[min] = 1;for (int i = 0; i < g.vexnum; i++) //对路径数组path 和路径权值数组dist 进行更新。{if ((S[i] == 0) && (dist[i] > dist[min] + g.arcs[min][i])){dist[i] = dist[min] + g.arcs[min][i];path[i] = min;}}num++;}displayPath(dist, path, start, g);delete[]path;delete[]dist;delete[]S;
}void menu()
{cout << "****《迪杰斯特拉算法求最短路径》*****" << endl;cout << "**1. 图的建立" << endl;cout << "**2. 输出图的信息" << endl;cout << "**3. 求图的最短路径" << endl;cout << "**4. 退出" << endl;cout << "____________________________________________" << endl;
}void deletescreen()
{system("pause");system("cls");
}int main()
{void menu();void deletescreen();AMGraph g1;//menu();string choose;while (true){menu();cin >> choose;if (choose == "1"){g1.creat_graph();cout << endl << "图建立成功!" << endl;deletescreen();}else if (choose == "2"){g1.print();deletescreen();}else if (choose == "3"){Dijkstra(g1);deletescreen();}else if (choose == "4"){cout << "退出成功!" << endl;exit(0);}else{cout << "输入有误!请重新输入" << endl;deletescreen();}}return 0;
}
五、测试情况:
测试一:
求图片中
1.源点为A到其它顶点的最小路径
2.源点为D到其它顶点的最小路径
测试结果:
1.建图
2.图的信息:
3.A到其它顶点的最小路径
4.D到其它顶点的最小路径
测试二:
1.测试案例:
2.求以 0 作为源点,到其它顶点的最短路径:
感谢你的收看,希望这可以帮助到你。
Dijkstra算法实现求有向图中一顶点到其余各个顶点的最短路径相关推荐
- 直观地简单理解Tarjan算法(寻找有向图中的强连通图)
简单理解Tarjan算法 按照百度百科的播报应该是读成['ta:rdʒən]?看过了几篇网络上的解释虽然都讲得比较具体但刚开始都难以理解,所以打算写一个更直观的理解方式. Tarjan算法是求 ...
- 最短路径:Dijkstra算法(求单源最短路径)Floyd算法(求各顶点之间最短路径)
最短路径: 在一个带权图中,顶点V0到图中任意一个顶点Vi的一条路径所经过边上的权值之和,定义为该路径的带权路径长度,把带权路径最短的那条路径称为最短路径. DiskStra算法: 求单源最短路径,即 ...
- 求有向图中两点最短距离java_Java 迪杰斯特拉算法实现查找最短距离
迪杰斯特拉算法 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题.迪杰斯特拉算法主要特点是 ...
- (算法)求数组中数字组合(可多值组合)相加最接近目标数的组合(可能多个)
今天没事,撸一道算法题 题目要求: 给出一个升序排序的可能重复值的数字数组和一个目标值其中目标值大于数组中最小数,求数组中数字组合(可多值组合)相加最接近目标数的组合(可能多个)不考虑空间复杂 ...
- 【POJ - 3259 】Wormholes(Bellman_Ford或spfa算法,判断有向图中是否存在负环)
题干: 农夫约翰在探索他的许多农场,发现了一些惊人的虫洞.虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500 ...
- 克鲁斯卡尔算法c语言,克鲁斯卡尔算法发现求有向图出错
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 void gdyx(gre*g) { int i,a[20]; for(i=0;iv;i++) a[i]=0; for(i=0;iv;i++) if(!a ...
- 图算法——求最短路径(Dijkstra算法)
目录 一.什么是最短路径 二.迪杰斯特拉(Dijkstra)算法 三.应用Dijkstra算法 (1) Dijkstra算法函数分析 求图的最短路径在实际生活中有许多应用,比如说在你在一个景区的某个景 ...
- 数据结构——图——迪杰斯特拉(Dijkstra )算法
数据结构--图--迪杰斯特拉(Dijkstra )算法 这是一个按路径长度递增的次序产生最短路径的算法.它的思路大体是这样的. 比如说要求图7-7-3中顶点v0到顶点v1的最短距离,没有比这更简单的了 ...
- Dijkstra算法的思想
1. Dijkstra算法是求图中某一点到其他点的最短距路.即单源最短路径问题,该算法不能处理负权边,该算法求出的是图中某一点src,到其他所有点的最短距离. 2. 该算法的思想是将图中的点分为两类, ...
最新文章
- ANDROID_NDK的path,如何在Android Studio中设置NDK_PROJECT_PATH
- ATM信元的交换方式为?
- 你知道Material Type(ROH,HALB,FERT…)为什么缩写是ROH,HALB,FERT吗?哈哈哈
- Hadoop 停止hdfs和yarn的命令
- 海信FW3010-5000H千兆防火墙
- java反射 数组类型_Java反射-数组
- 一文知晓浪潮云海OS在SPEC Cloud测试中的调优实践!
- mysql升级准备工作
- 理论+实践,带你掌握动态规划法
- CraftAR入门教程
- 《You can do it!》的chapter 2笔记
- java地铁最短,地铁最短路径
- [转] Python标准库的threading.Thread类
- vc6 往mdb写入信息_HBase运维 | 一张表写入异常引起的HBase Replication 队列堆积
- 运用c语言和Java写九九乘法表
- Spring Boot 应用上传文件时报错
- windows和Linux下西部数据C1门解决方法
- 360修复上不了网络连接服务器失败,360断网急救箱网络连接配置修复不了怎么办-修复不了的解决办法...
- python 读写三菱PLC数据,使用以太网读写Q系列,L系列,Fx系列的PLC数据
- Android内存优化工具
热门文章
- 仿麦包包首页tab轮换图jQuery
- Training Region-based Object Detectors with Online Hard Example Mining论文讲解
- 2019多校第九场 HDU6681 Rikka with Cake(欧拉图论定理,线段树)
- 简述使用混合传递参数时的基本原则_化工原理复习资料
- 企业SCRM渠道活码功能介绍
- 快手2020校园招聘秋招笔试--算法C试卷 练习 解题报告 Apare_xzc
- 微信小程序表单数据提交到php处理,数据插入数据库小案例。
- Docker Swarm (服务发现和负载均衡原理)
- 计算机网络专业单招考试科目,2018年辽宁交专单独招生对口升学类招生计算机网络专业综合课考试大纲...
- EdgeRouter ER-X 定时自动重启设置