用Dijkstra算法输出最短路径以及对应的最小权值

Posted C语言三人行+

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用Dijkstra算法输出最短路径以及对应的最小权值相关的知识,希望对你有一定的参考价值。

    看《数据结构》的时候,发现教科书上提供的算法貌似只是把最短路径上的顶点放到一个二维数组里头就完事了,却没有给出路径上顶点的输出次序。一个顶点数组就叫做最短路径,编者也太不负责任了吧,好歹也给个根据得到的路径顶点数组求该路径的方法吧?还是编者想让读者有自己思考的余地??不过回头想想,如果通过那个路径顶点的二维数组,按照路径长度从小到大,输出长路径时先输出短路径包含的顶点的原则来分别输出这些路径,应该还是能搞定的(虽然没试过……)。

        不过,自己还是重新写了一个与教科书有点不同的Dijkstra算法出来,算法基本思想还是一样的,只是这里的辅助变量有些区别而已,同时也给出了一个利用栈来求最短路径中顶点的输出次序。程序在VC++6.0编译通过了,而算法的具体过程如下:

#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef char VertexType;//顶点类型
#define INFINITY 2147483647//表示两顶点不相连的权值为2147483647
#define MAX_VERTEX_NUM 20//表示图中最大顶点数
#define MAX_STACK_NUM MAX_VERTEX_NUM

typedef struct Stack{
int vertex[MAX_STACK_NUM];
int top;
}Stack;

//栈初始化
Status InitStack(Stack *s){
int i;
for(i=0;i<MAX_STACK_NUM;++i)
   s->vertex[i]=0;
s->top=-1;
return OK;
}

//入栈
Status Push(Stack *s,int v){
if(s->top==MAX_STACK_NUM-1){
   printf("栈满,无法入栈!\n");
   return ERROR;
}
s->vertex[++s->top]=v;
return OK;
}

//退栈
Status Pop(Stack *s,int *e){
if(s->top==-1){
   printf("空栈无法弹出!\n");
   return ERROR;
}
*e=s->vertex[s->top--];
return OK;
}

//判断栈是否为空
Status StackEmpty(Stack s){
if(s.top==-1)
   return TRUE;
return FALSE;
}

typedef struct MGraph{
VertexType vexs[MAX_VERTEX_NUM];//顶点数组
int adj[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//图的邻接矩阵
int vexnum,arcnum;
}MGraph;

//顶点定位,不存在则返回-1
int LocateVex(MGraph G,VertexType v){
int i;
for(i=0;i<G.vexnum;++i)
   if(G.vexs[i]==v)
    return i;
   return -1;
}

//建立无向图邻接矩阵
Status CreateGraph(MGraph *G){
VertexType v1,v2;
int i,j,k;

printf("构造有向图\n\n");
printf("请输入顶点个数:");
scanf("%d",&G->vexnum);
if(G->vexnum>MAX_VERTEX_NUM) return ERROR;
printf("输入边数:");
scanf("%d",&G->arcnum);
if(G->arcnum>MAX_VERTEX_NUM*(MAX_VERTEX_NUM-1)/2) return ERROR;//边输入有误
printf("\n");

for(i=0;i<G->vexnum;++i){
   getchar();
   printf("输入第%d个顶点:",i+1);
   scanf("%c",&G->vexs[i]);
}

for(i=0;i<G->vexnum;++i)
   for(j=0;j<G->vexnum;++j)
    G->adj[i][j]=INFINITY;//邻接矩阵初始化
   printf("\n");
  
   for(k=0;k<G->arcnum;++k){
    getchar();
    printf("输入第%d条边对应的起点和终点:",k+1);
    scanf("%c%c",&v1,&v2);
    i=LocateVex(*G,v1);
    j=LocateVex(*G,v2);
    printf("输入该边的权值:");
    scanf("%d",&G->adj[i][j]);
   }
   return OK;
}

//返回v的第一个邻接点位置,不存在则返回-1
int FirstAdjVex(MGraph G,int v){
int j;
for(j=0;j<G.vexnum;++j)
   if(G.adj[v][j]==1)
    return j;
   return -1;
}

//返回v相对于w的下一个邻接点,没有则返回-1
int NextAdjVex(MGraph G,int v,int w){
int k;
for(k=w+1;k<G.vexnum;++k)
   if(G.adj[v][k]==1)
    return k;
   return -1;
}

//打印邻接矩阵
void Print_Graph_Array(MGraph g){
int i,j;
printf("\n图邻接矩阵是:\n ");
for(i=0;i<g.vexnum;++i)
   printf(" %c",g.vexs[i]);
for(i=0;i<g.vexnum;++i){
   printf("\n%c ",g.vexs[i]);
   for(j=0;j<g.vexnum;++j){
    if(g.adj[i][j]==INFINITY)
     printf("%d ",g.adj[i][j]-INFINITY);
    else
     printf("%d ",g.adj[i][j]);
   }
}
printf("\n\n");
}

//Dijkstra算法
void ShortestPath_Dij(MGraph g,int v0,int D[],int P[]){
//D[]存放到达各个顶点的最小权值之和
//路径数组P[]用于求各个顶点最短路径中顶点的先后次序,如果P[i]不等于i,则表示在最短路径中到达点vi前必须先到达点v(P[i])

int i,j;
int location_min,min;//location_min存放每一次“路径试探”时找到的最小权值min对应的顶点的下标
int final[MAX_VERTEX_NUM];//数组final[i]为true当且仅当vi已经找到从v0出发的最短路径

for(j=0;j<g.vexnum;++j){
   D[j]=g.adj[v0][j];//数组D[]初始化
   final[j]=FALSE;//数组final[]初始化
  
   //数组P[]初始化
   if(g.adj[v0][j]!=INFINITY)
    P[j]=j;
   else
    P[j]=INFINITY;
}
final[v0]=TRUE;

for(i=1;i<g.vexnum;++i){
   min=INFINITY;

   //求每一次“路径试探”时最小权值对应的顶点的下标,并保存到location_min中
   for(j=0;j<g.vexnum;++j){
    if(final[j]) continue;
    if(D[j]<min) {
     min=D[j];
     location_min=j;
    }
   }
   final[location_min]=TRUE;
  
   //试探vertex[location_min]到其余的某个顶点vertex[j]的权值与D[location_min]之和是否小于D[j]
   for(j=0;j<g.vexnum;++j){
    if(final[j]) continue;
    if(g.adj[location_min][j]!=INFINITY && D[location_min]+g.adj[location_min][j]<D[j]){
     D[j]=D[location_min]+g.adj[location_min][j];
     P[j]=location_min;
    }
   }

}

//根据求得的路径数组P[]依次打印各条最短路径的线路及其最小权值和
void Print_ShortestPaths(MGraph g,int v0,int D[],int P[],int vertexnum){
int i,j;
int e;
Stack s;

for(i=0;i<vertexnum;++i){
   if(i==v0) continue;

   printf("%c到%c的最短路径是:",g.vexs[v0],g.vexs[i]);
   if(P[i]==INFINITY) 
    printf("无\n\n");
   else{
    j=i;
    InitStack(&s);
    Push(&s,j);
    while(g.vexs[j]!=g.vexs[P[j]]){
     Push(&s,P[j]);
     j=P[j];
    }//如果g.vexs[j]与g.vexs[P[j]]不相等,则表示在最短路径中输出顶点g.vexs[j]前要先输出顶点g.vexs[p[j]]
    Push(&s,v0);
    while(!StackEmpty(s)){
     Pop(&s,&e);
     printf("%c ",g.vexs[e]);
    }
    printf("\n该路径的总权值为:%d\n\n",D[i]);
   }//从路径的终点到起点依次进栈,最后通过栈将路径的各顶点输出
}
}


void main(){
MGraph g;
char quit;
VertexType startpoint;
int v0;
int D[MAX_VERTEX_NUM],P[MAX_VERTEX_NUM];
Stack s;

do {
   if(!CreateGraph(&g)){
    printf("输入错误!\n");
    goto ErrMrk;
   }
  
   Print_Graph_Array(g);

   printf("输入路径起点:");
   getchar();
   startpoint=getchar();
   printf("\n");
   v0=LocateVex(g,startpoint);
   ShortestPath_Dij(g,v0,D,P);//求起点到各个顶点的最短路径
   Print_ShortestPaths(g,v0,D,P,g.vexnum);//打印各条最短路径及相应的总权值
  
   printf("\n\n");

ErrMrk: printf("退出请按0,重新测试请按任意键:");
   getchar();
   quit=getchar();
   system("cls");
} while(quit!='0');
}


以上是关于用Dijkstra算法输出最短路径以及对应的最小权值的主要内容,如果未能解决你的问题,请参考以下文章

用Dijkstra算法求最短路径

经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)

图 实验七 采用Dijkstra算法求带权有向图的最短路径

Dijkstra算法

图论最短路径问题(图的绘制以及Dijkstra算法和Bellman‐Ford算法)

图论最短路径问题(图的绘制以及Dijkstra算法和Bellman‐Ford算法)