图的最小生成树及最短路径算法
图的最小生成树算法及最短路径算法
——Prim算法,Dijkstra算法及Floyd算法
概述
我的上一篇博客图的DFS与BFS(C++)中谈到了用C++实现图的构建和遍历。这次,我仍然准备构建储存结构为邻接矩阵的无向图,来实现求图的最小生成树的Prim算法,求图单源最短路径的Dijkstra算法,以及求图多源最短路径的Floyd算法。其实求最小生成树还有一种Kruskal算法,但因为此例用邻接矩阵储存,不方便表达边与两个邻接点及权值的关系,故之后我会另开一篇叙述。
代码
1.引入必要头文件,对图的抽象数据类型进行声明。这里定义3个接口,分别对应用于实现3个算法。
#include<iostream>
#include<vector>
#include<mem.h>
int inf=9999;
using namespace std;
//Graph为封装的类模板
template <class T>
struct Graph{
//储存顶点
vector<T> vertex;
//储存边
vector<vector<int>> edge;
//标记数组
bool book[100];
Graph(int n,int m);
~Graph();
void Prim(int cur);
void Dijkstra(int cur);
void Floyd();
};
2.图的构造函数和析构函数:
template <class T>
Graph<T>::Graph(int n,int m){
vertex.resize(n+1);
edge.resize(n+1);
for(int i=0;i<n+1;i++){
edge[i].resize(n+1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) edge[i][j]=0;
else edge[i][j]=inf;
}
}
cout<<"请依次输入各条边的两个邻点及权值(无向)"<<endl;
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
edge[a][b]=edge[b][a]=c;
}
cout<<endl;
for(int i=1;i<=n;i++){
vertex[i]=i; //顶点值用编号赋值,方便理解
}
memset(book,0,100);
}
template <class T>
Graph<T>:: ~Graph(){
vertex.clear();
edge.clear();
}
3.Prim算法实现
template <class T>
void Graph<T>::Prim(int cur){
vector<int> dis(vertex.size());
for(int i=1;i<=vertex.size()-1;i++){
dis[i]=edge[cur][i];
}
//表示1号顶点已加入最小生成树
int count=1;
cout<<vertex[cur]<<"——";
book[cur]=1;
int sum=0;
while(count<vertex.size()-1){
int min=inf;
int j;
for(int i=1;i<=vertex.size()-1;i++){
if(book[i]==0&&dis[i]<min){
min=dis[i];
j=i;
}
}
cout<<vertex[j];
sum += dis[j];
book[j]=1;
for(int k=1;k<=vertex.size()-1;k++){
if(book[k]==0&&edge[j][k]<dis[k]){
dis[k]=edge[j][k];
}
}
count++;
if(count<vertex.size()-1) cout<<"——";
}
cout<<endl;
cout<<"最小生成树权值和为:"<<sum<<endl;
}
4.Floyd算法实现
template <class T>
void Graph<T>::Floyd(){
/*设下标为k的顶点为从i到j的路径中途可能经过的点
如果该点而能使i到j路径收缩,则更新i到j路径 */
for(int k=1;k<=vertex.size()-1;k++){
//i,j为任意路径的起始点和终点
for(int i=1;i<=vertex.size()-1;i++){
for(int j=1;j<=vertex.size()-1;j++){
//路径收缩
if(edge[i][k]+edge[k][j]<edge[i][j]){
edge[i][j]=edge[i][k]+edge[k][j];
}
}
}
}
//打印出任意两点间的最短路径
for(int i=1;i<=vertex.size()-1;i++){
for(int j=1;j<=vertex.size()-1;j++){
if(edge[i][j]<inf&&edge[i][j]!=0){
cout<<i<<"->"<<j<<"最短路径长度为 "<<edge[i][j]<<endl;
}
}
}
}
5.Dijkstra算法实现
template <class T>
void Graph<T>::Dijkstra(int cur){
vector<int> dis(vertex.size());
for(int i=1;i<=vertex.size()-1;i++){
dis[i]=edge[cur][i];
}
int j;
//表示1号顶点已加入路径确定的集合中
book[1]=1;
while(count<vertex.size()-1){
int min=inf;
for(int i=1;i<=vertex.size()-1;i++){
if(book[i]==0&&dis[i]<min){
min=dis[i];
j=i;
}
}
book[j]=1;
for(int k=1;k<=vertex.size()-1;k++){
if(edge[j][k]+dis[j]<dis[k]&&edge[j][k]<inf){
dis[k]=dis[j]+edge[j][k];
}
}
count++;
}
for(int i=1;i<=vertex.size()-1;i++){
cout<<cur<<"->"<<i<<"最短路径长度为"<<dis[i]<<endl;
}
}
6.最后,main函数实例化图对象,调用对象方法,实现算法。(注意:每次调用用函数接口后要将标记数组重新初始化为0)
int main(){
Graph<int>* G=new Graph<int>(5,5);
cout<<"Prim算法求最小生成树如下:"<<endl;
G->Prim(1);
memset(G->book,0,100);
cout<<endl;
cout<<"Dijkstra算法求单源最短路径如下:"<<endl;
G->Dijkstra(1);
memset(G->book,0,100);
cout<<endl;
cout<<"Floyd算法求任意两点最短路径如下:"<<endl;
G->Floyd();
cout<<endl;
system("pause");
return 0;
}
输出
数学是符号的艺术,音乐是上界的语言。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~