数据结构-图的最短路径算法实现
十四、图的最短路径算法实现
1、采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的 Dijkstra 算法。
/*采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的 Dijkstra 算法。*/
#include<stdio.h>
#include<stdlib.h>
//#include<limits.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INFINITY 32767//最大值
#define MAX_VERTEX_NUM 20//最大顶点个数
typedef int Status;
typedef int VRType;
typedef int InfoType;
typedef enum {DG,DN,UDG,UDN}GraphKind;//{有向图,有向网,无向图,无向网}
typedef struct ArcCell{
VRType adj;//VRType是顶点关系类型。对无权图,用0或1
//表示相邻否;对带权图,则为权值类型
InfoType *info;//该弧相关信息的指针
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef char VertexType;
typedef struct{
VertexType vexs[MAX_VERTEX_NUM];//顶点向量
AdjMatrix arcs;//邻接矩阵
int vexnum,arcnum;//图的当前顶点数和弧数
GraphKind kind;//图的种类标志
}MGraph;
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];
int LocateVex(MGraph G,char v){
int i;
for(i=0;i<G.vexnum;++i)
if(G.vexs[i]==v) return i;
return -1;
}
Status CreateDG(MGraph &G){
//采用数组(邻接矩阵)表示法,构造有向图G。
int i,j,k;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj:\n",k+1);
scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=1;//弧<v1,v2>的权值
//G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateDG
Status CreateDN(MGraph &G){
//采用数组(邻接矩阵)表示法,构造有向网G。
int i,j,k,w;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=w;//弧<v1,v2>的权值
//G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateDN
Status CreateUDG(MGraph &G){
//采用数组(邻接矩阵)表示法,构造无向图G。
int i,j,k;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj:\n",k+1);
scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=1;//弧<v1,v2>的权值
//G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateUDG
Status CreateUDN(MGraph &G){
//采用数组(邻接矩阵)表示法,构造无向网G。
int i,j,k,w;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=w;//弧<v1,v2>的权值
G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateUDN
Status CreateGraph(MGraph &G){
//采用数组(邻接矩阵)表示法,构造图G
printf("请输入图的种类:0表示DG,1表示DN,2表示UDG,3表示UDN\n");
scanf("%d",&G.kind);//自定义输入函数,读入一个随机值
switch(G.kind){
case DG:return CreateDG(G);//构造有向图G
case DN:return CreateDN(G);//构造有向网G
case UDG:return CreateUDG(G);//构造无向图G
case UDN:return CreateUDN(G);//构造无向网G
default:return ERROR;
}
}//CreateGraph
void list(MGraph G){
int i,j;
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].adj==INFINITY)
printf("%4s","∞");//∞ alt+41438
else
printf("%4d",G.arcs[i][j].adj);
printf("\n");
}
}
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix &P,ShortPathTable &D){
//用Dijkstra算法求有向网的v0顶点到其余顶点v的最短路径p[v]及带权长度D[v]
int v,w,i,j,min;
Status final[MAX_VERTEX_NUM];
for(v=0;v<G.vexnum;++v){
final[v]=FALSE;
D[v]=G.arcs[v0][v].adj;
for(w=0;w<G.vexnum;++w)
P[v][w]=FALSE;
if(D[v]<INFINITY){
P[v][v0]=TRUE;
P[v][v]=TRUE;
}
}
D[v0]=0;
final[v0]=TRUE;
for(i=1;i<G.vexnum;++i){
min=INFINITY;
for(w=0;w<G.vexnum;++w)
if(!final[w])
if(D[w]<min)
{
v=w;
min=D[w];
}
final[v]=TRUE;
for(w=0;w<G.vexnum;++w){
if(!final[w]&& min < INFINITY&&G.arcs[v][w].adj < INFINITY && (min + G.arcs[v][w].adj < D[w]))
{ /* 修改D[w]和P[w],w∈V-S */
D[w] = min + G.arcs[v][w].adj;
for (j = 0; j < G.vexnum; ++j)
P[w][j] = P[v][j];
P[w][w] = TRUE;
}
}
}
for(i=0;i<G.vexnum;++i){
if(i!=v0){
printf("%3c %3c ",G.vexs[v0],G.vexs[i]);
if(D[i]!=INFINITY) printf("%5d ",D[i]);
else printf("%5s ","无");
printf("(");
for(j=0;j<G.vexnum;++j)
if(P[i][j])printf("%c",G.vexs[j]);
printf(")");
printf("\n");
}
}
}
int main(){
MGraph G;
int v0;
PathMatrix P;
ShortPathTable D;
CreateGraph(G);
list(G);
printf("输入源点序号v0:\n");
scanf("%d",&v0);
printf("输出从源点%d到其余顶点的最短路径如下:\n",v0);
printf("始点 终点 路径长度 最短路径\n");
ShortestPath_DIJ(G,v0,P,D);
printf("\n");
return 0;
}
2、采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的的 Floyd 算法。
/*采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的 Floyd 算法。*/
#include<stdio.h>
#include<stdlib.h>
//#include<limits.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INFINITY 32767//最大值
#define MAX_VERTEX_NUM 20//最大顶点个数
typedef int Status;
typedef int VRType;
typedef int InfoType;
typedef enum {DG,DN,UDG,UDN}GraphKind;//{有向图,有向网,无向图,无向网}
typedef struct ArcCell{
VRType adj;//VRType是顶点关系类型。对无权图,用0或1
//表示相邻否;对带权图,则为权值类型
InfoType *info;//该弧相关信息的指针
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef char VertexType;
typedef struct{
VertexType vexs[MAX_VERTEX_NUM];//顶点向量
AdjMatrix arcs;//邻接矩阵
int vexnum,arcnum;//图的当前顶点数和弧数
GraphKind kind;//图的种类标志
}MGraph;
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int DistancMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
int LocateVex(MGraph G,char v){
int i;
for(i=0;i<G.vexnum;++i)
if(G.vexs[i]==v) return i;
return -1;
}
Status CreateDG(MGraph &G){
//采用数组(邻接矩阵)表示法,构造有向图G。
int i,j,k;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj:\n",k+1);
scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=1;//弧<v1,v2>的权值
//G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateDG
Status CreateDN(MGraph &G){
//采用数组(邻接矩阵)表示法,构造有向网G。
int i,j,k,w;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
if(i==j) G.arcs[i][j].adj=0;
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=w;//弧<v1,v2>的权值
//G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateDN
Status CreateUDG(MGraph &G){
//采用数组(邻接矩阵)表示法,构造无向图G。
int i,j,k;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj:\n",k+1);
scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=1;//弧<v1,v2>的权值
//G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateUDG
Status CreateUDN(MGraph &G){
//采用数组(邻接矩阵)表示法,构造无向网G。
int i,j,k,w;
VertexType v1,v2;
printf("输入顶点数G.vexnum:");
scanf("%d",&G.vexnum);
printf("输入边数G.arcnum:");
scanf("%d",&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++){
printf("输入顶点G.vexs[%d]:",i);
scanf("%c",&G.vexs[i]);
getchar();
}//构造顶点向量
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j){
G.arcs[i][j].adj=INFINITY;//{adj,info}
G.arcs[i][j].info=NULL;
}
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
getchar();
i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
G.arcs[i][j].adj=w;//弧<v1,v2>的权值
G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
}
return OK;
}//CreateUDN
Status CreateGraph(MGraph &G){
//采用数组(邻接矩阵)表示法,构造图G
printf("请输入图的种类:0表示DG,1表示DN,2表示UDG,3表示UDN\n");
scanf("%d",&G.kind);//自定义输入函数,读入一个随机值
switch(G.kind){
case DG:return CreateDG(G);//构造有向图G
case DN:return CreateDN(G);//构造有向网G
case UDG:return CreateUDG(G);//构造无向图G
case UDN:return CreateUDN(G);//构造无向网G
default:return ERROR;
}
}//CreateGraph
void list(MGraph G){
int i,j;
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].adj==INFINITY)
printf("%4s","∞");//∞ alt+41438
else
printf("%4d",G.arcs[i][j].adj);
printf("\n");
}
}
void ShortestPath_FLOYD(MGraph G, PathMatrix &P, DistancMatrix &D)
{ /* 用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其 */
/* 带权长度D[v][w]。若P[v][w][u]为TRUE,则u是从v到w当前求得最短 */
/* 路径上的顶点。算法7.16 */
int u, v, w, i;
for (v = 0; v < G.vexnum; v++) /* 各对结点之间初始已知路径及距离 */
for (w = 0; w < G.vexnum; w++)
{
D[v][w] = G.arcs[v][w].adj;
for (u = 0; u < G.vexnum; u++)
P[v][w][u] = FALSE;
if (D[v][w] < INFINITY) /* 从v到w有直接路径 */
{
P[v][w][v] = TRUE;
P[v][w][w] = TRUE;
}
}
for (u = 0; u < G.vexnum; u++)
for (v = 0; v < G.vexnum; v++)
for (w = 0; w < G.vexnum; w++)
if (D[v][u] + D[u][w] < D[v][w]) /* 从v经u到w的一条路径更短 */
{
D[v][w] = D[v][u] + D[u][w];
for (i = 0; i < G.vexnum; i++)
P[v][w][i] = P[v][u][i] || P[u][w][i];
}
printf("输出每一对顶点之间的最短路径长度如下:\n");
for(v=0;v<G.vexnum;++v){
printf("%c----",G.vexs[v]);
for(w=0;w<G.vexnum;++w)
if(D[v][w]==INFINITY)
printf("%4s","∞");
else
printf("%4d",D[v][w]);
printf("\n");
}
printf("输出每一对顶点之间的最短路径如下:\n");
for(v=0;v<G.vexnum;++v){
printf("%c----",G.vexs[v]);
for(w=0;w<G.vexnum;++w){
for(u=0;u<G.vexnum;++u)
if(P[v][w][u])printf("%c",G.vexs[u]);
else printf("∞");
printf(" ");
}
printf("\n");
}
}
int main(){
MGraph G;
PathMatrix P[MAX_VERTEX_NUM];
DistancMatrix D;
CreateGraph(G);
list(G);
ShortestPath_FLOYD(G,*P,D);
printf("\n");
return 0;
}