#include <iostream>
#define MAXVEX 5 //结点数(初始默认6顶点,更改的话直接在这里修改即可)
#define MAXEDGE 8 //边数(初始默认10条边,更改的话直接在这里修改即可)
#define INFINITY 65535 //表示无穷大
using namespace std;
//下面代码是有向图的邻接矩阵(某顶点到其他顶点的最短距离)单源最短路径的迪杰斯特拉算法
//注意点: 下标0的位置都不用,所以要多开辟一个空间
//注意点:此程序主要通过迪杰特斯拉得到dist数组的值和pre数组
//注意点:最后的输出结是通过这两个数组来的(借助栈)
//若改为无向图的邻接矩阵迪杰斯特拉算法,则:
//增加下面的一句代码g.matrix[n][m]=1;
typedef struct
{
int vexNum; //顶点数
int edgeNum; //边数
int matrix[MAXVEX+1][MAXVEX+1]; //二维数组表示矩阵
char vexinfo[MAXVEX+1]; //存放结点数组的值(如A,B,C,D)
}AdjMatr; //邻接矩阵
typedef struct sqstack
{
int *elem;
int top;
}SqStack; //栈
/*****************初始化静态栈******************/
void InitStack(SqStack & s)
{
s.elem =new int[MAXVEX+1];
s.top=0;
}
/******************压栈*************************/
//进栈是从下标1开始存放,0位置不存放数据
void Push(SqStack &s , int e)
{
s.top++;
s.elem[s.top]=e;
}
/******************出栈*************************/
void Pop(SqStack &s , int &e)
{
e=s.elem[s.top];
s.top--;
}
/******************判断是否空栈*****************/
int Emptystack(SqStack &s)
{
if(s.top<1)
return 0;
else
return 1;
}
/*********************初始化邻接矩阵************************/
void initAdjMatr(AdjMatr &g )
{
g.vexNum = MAXVEX; //顶点数
g.edgeNum = MAXEDGE; //边数
//初始化矩阵信息,初始为,一个不可能的数字表示这两个顶点之间不存在边
for(int i=1;i<=MAXVEX;i++)
{
for(int j=1;j<=MAXVEX;j++)
g.matrix[i][j]=INFINITY;
}
//初始化结点信息,(如A,B,C,D)
for(int i=1;i<=MAXVEX;i++)
{
cout<<"请输入第"<<i<<"个结点的信息:";
cin>>g.vexinfo[i];
}
}
//通过结点信息(A,B,C,D之类)来查找对应矩阵下标
/*********************确定边在矩阵的位置*********************/
void locata(AdjMatr &g,char &vex1,char &vex2, int &m, int &n)
{
for(int i =1;i<=MAXVEX;i++)
{
if(vex1 == g.vexinfo[i])
m=i;
if(vex2 == g.vexinfo[i])
n=i;
}
}
/*********************创建图对应的邻接矩阵************************/
void setAdjMatr(AdjMatr &g)
{
//根据输入的两个顶点,来更新矩阵的值
for(int i=1;i<=g.edgeNum;i++)
{
int weight;//两边之间的权值
char vex1,vex2; //接受输入的两个顶点,来表示从vex1到vex2这条边
cout<<"请输入第"<<i<<"条边的信息(形如A B 7,表示从A到B的一条边权值7):";
cin>>vex1>>vex2>>weight;
int m,n; //m和n是用来接受vex1和vex2所在的下标值,好据此更新矩阵相应位置的值
locata(g,vex1,vex2,m,n);
g.matrix[m][n]=weight;
//g.matrix[n][m]=weight;//无向图邻接矩阵对称,加上这句代码就是无向图的邻接矩阵了
}
}
/**********************单源最短路径之迪杰斯特拉算法************************/
void Dijkstra(AdjMatr &g,int *dist,int *pre,int *visited,int first)
{
int k;
int v=first; //表示要求的是从顶点v到其他顶点的最短路径,如果要求别的顶点到其他顶点的最短路径直接在这里修改即可
for(int i=1;i<=MAXVEX;i++) //初始化数据
{
visited[i]=0; //表示初始时,全为未知最短路径的状态
dist[i]=g.matrix[v][i];//将与源点v有连线的顶点加上权值
pre[i]=0;
}
for(int i=1;i<=MAXVEX;i++)
{ //初始化全部顶点的直接前驱为
if(dist[i]==INFINITY) //说明v和i不是邻接点,此时设置i的直接前驱为-1,表示无直接前驱
pre[i]=-1;
else //说明v和i是邻接点,此时设置i的直接前驱为1
pre[i]=v;
}
dist[v]=0; //源点v到v的路径为0
visited[v]=1; //表示源点到源点的最短路径已经找到
//开始进行循环,每次循环会找到一条源点到某个顶点的最短路径,n个结点则一共要找n-1条最短路径,所以循环n-1次
for(int i=2;i<=MAXVEX;i++)
{
int Min = INFINITY;
//此循环是要找出离源点v最近的顶点和距离
for(int j=1;j<=MAXVEX;j++)
{
if(visited[j]==0 && dist[j] < Min)
{
k=j;//离源点v最近的顶点k下标
Min=dist[j]; //离源点v最近的顶点k的距离
}
}
visited[k]= 1;//表示已经找到离源点最近的顶点k
//现在就是借助已找到的最短距离(即visited[k]=0)的顶点,看看源点到其他顶点的路径会不会更短
for(int j=1;j<=MAXVEX;j++)
{ //如果源点借助k顶点到j的路径,比源点直接到j的路径短的话
//其实这里主要是看看跟k相邻的顶点的dist值需不需要更改而已
if(visited[j] ==0 && (Min + g.matrix[k][j] < dist[j]))
{ //说明借助k找到了源点到顶点j的更短路径,此时修改dist[j]和pre[j]的值
dist[j]=Min + g.matrix[k][j];
pre[j]=k;
}
}
}
}
/*******************查看dist、pre及visited数组********************/
//这个函数主要是方便理解这三个数组值的变化
void showArray(int *dist, int*pre, int *visited)
{
cout<<"dist数组情况:"<<endl;
for(int i=1;i<=MAXVEX;i++)
cout<<dist[i]<<" ";
cout<<endl;
cout<<"pre数组情况:"<<endl;
for(int i=1;i<=MAXVEX;i++)
cout<<pre[i]<<" ";
cout<<endl;
cout<<"visited数组情况:"<<endl;
for(int i=1;i<=MAXVEX;i++)
cout<<visited[i]<<" ";
cout<<endl;
}
/********************利用栈输出单源最短路径***********************/
void ShowDijkstra(AdjMatr &g,int *dist, int*pre, int v) //v是源点
{
int temp;
cout<<"迪杰特斯拉算法,单源"<<v<<"到其他顶点的最短路径如下:"<<endl;
for(int i=1;i<=MAXVEX;i++)
{
temp=i;
SqStack s; //创建一个栈
InitStack(s); //初始化栈
if(pre[temp] != -1) //表示无直接前驱,即源点v到该点无路径
{
while(temp!=-1) //把顶点压栈,这里利用的是pre数组的直接前驱作用
{
Push(s,temp);
temp=pre[temp];
}
}
if(Emptystack(s) != 0 ) //栈非空
{
cout<<g.vexinfo[v]<<"->"<<g.vexinfo[i]<<"的最短路径是: "<<dist[i]<<" ";
while(s.top >=1)
{ //这里的if-else是用来控制"->"
if(s.top>1)
{
Pop(s,temp);
cout<<g.vexinfo[temp]<<"->";
}else//表示是最后一个元素了
{
Pop(s,temp);
cout<<g.vexinfo[temp]<<endl;
}
}
}else //栈为空,表明从源点v到该点无路径
cout<<g.vexinfo[v]<<"->"<<g.vexinfo[i]<<"的最短路径是: "<<dist[i]<<endl;
}
}
int main()
{
int dist[MAXVEX+1]; //表示顶点v到顶点i的最短路径
int pre[MAXVEX+1]; //表示从源点到顶点i的最短路径上i的直接前驱结点,无直接前驱则该值为-1
int visited[MAXVEX+1] ; //表示是否求得顶点v到i的最短路径,求得则为1,没求得就为0
AdjMatr g;
initAdjMatr(g);
setAdjMatr(g);
int v = 1; //表示要求的是从顶点1到其他顶点的最短路径,如果要求别的顶点到其他顶点的最短路径直接在这里修改即可
Dijkstra(g,dist,pre,visited,v);
showArray(dist,pre,visited); //显示这三个数组的情况
ShowDijkstra(g,dist,pre,v); //利用这三个数组输出单源最短路径的具体情况
return 0;
}
C++数据结构-图的单源最短路径迪杰斯特拉算法
猜你喜欢
转载自blog.csdn.net/weixin_43323201/article/details/84792404
今日推荐
周排行