首页 > 代码库 > 迪杰斯特拉算法求最短距离

迪杰斯特拉算法求最短距离

头文件:






#include <memory.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>


#include ".\source\common.h"
#include "lxbasic.h"




#define MAX_VEX_NUM  20
#define MAX_STR_LEN  20


#define INFINITY  999  //无穷大


//顶点结构
typedef struct tagVexType
{
int index;
char name[MAX_STR_LEN];
}VexType;


//弧结构
typedef struct tagArcType
{
int adj;//权值
}ArcType;




//图结构
typedef struct tagGraphic
{
VexType vexs[MAX_VEX_NUM];
ArcType arcs[MAX_VEX_NUM][MAX_VEX_NUM];
int vexnum;
int arcnum;//暂时无用
}Graphic;


//保存顶点V0到其余各顶点的最短路径权值和经过的节点路径
typedef struct tagPathFinal
{
int v0;//起始顶点编号
int D[MAX_VEX_NUM]; //最短路径的值(D[V])
int P[MAX_VEX_NUM][MAX_VEX_NUM];  //最短路径的路径(P[v])
}PathFinal;




//函数申明
//创建并初始化图
Graphic *CreateGraphic();




//画图打印
void PrintGraphic(Graphic *pGraphic);


//画图设置值
void SetGraphic(Graphic *pGraphic);


//销毁图
void DestroyGraphic(Graphic **ppGraphic);


//打印最短路径
void PrintShortestPath(Graphic *pGraphic,PathFinal *path);


//迪杰斯特拉求最短路径
void ShortestPath_DIJ(Graphic *pGraphic, PathFinal *path);


//测试程序
void TestCaseForGraphic();


源文件:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////







#include "dc_graph.h"




/*
关于返回局部指针变量的总结:
局部变量的指针是不能返回的,而局部指针变量是可以返回的。
1.局部变量的指针和局部指针变量是两个不同概念
2.局部变量在函数体结束后生命期也结束,它的指针(即它的地址)是无效变量的地址,所以函数不能返回这种地址值
3,局部指针变量在函数结束后生命期也结束,但它指向的变量或函数或任何存储实体的生命期没有结束,函数返回的指针(地址)就是有效的
*/


//创建并初始化图
Graphic *CreateGraphic()
{
    Graphic *pGraphic = (Graphic *)malloc(sizeof(Graphic));


NULL_PTR_RET_NULL(pGraphic)


pGraphic->vexnum = 0;
pGraphic->arcnum = 0;
memset(pGraphic->vexs,0,sizeof(VexType)*MAX_VEX_NUM);
memset(pGraphic->arcs,0,sizeof(ArcType)*MAX_VEX_NUM*MAX_VEX_NUM);


return pGraphic;
}


//画图
void PrintGraphic(Graphic *pGraphic)
{
    int i,j;


for(i=0;i<pGraphic->vexnum;i++)
{
        printf("    %s[%d]  ",pGraphic->vexs[i].name,pGraphic->vexs[i].index);
}
printf("\n");


    for(i=0;i<pGraphic->vexnum;i++)
{
printf("%s[%d]:",pGraphic->vexs[i].name,pGraphic->vexs[i].index);
for(j=0;j<pGraphic->vexnum;j++)
{
printf("%d   ",pGraphic->arcs[i][j]);
}
printf("\n");
}
}


//设置图的顶点和邻接矩阵信息(数据结构严蔚敏版187页图7.34)
/*
vex0[0]  vex1[1]  vex2[0]  vex3[0]  vex4[0]  vex5[0]
vex0[0]:  0        *        10       *        30       100
vex1[1]:  *        0        5        *        *        *
vex2[0]:  10       5        0        50       *        *
vex3[0]:  *        *        50       0        20       10
vex4[0]:  30       *        *        20       0        60
vex5[0]:  100      *        *        10       60       0
*/
void SetGraphic(Graphic *pGraphic)
{
int i,j;
    NULL_PTR_RET(pGraphic)


pGraphic->vexnum = 6;
pGraphic->arcnum = 8;


pGraphic->vexs[0].index = 0;
strncpy(pGraphic->vexs[0].name,"vex0",MAX_STR_LEN);


pGraphic->vexs[1].index = 1;
strncpy(pGraphic->vexs[1].name,"vex1",MAX_STR_LEN);


pGraphic->vexs[2].index = 0;
strncpy(pGraphic->vexs[2].name,"vex2",MAX_STR_LEN);


pGraphic->vexs[3].index = 0;
strncpy(pGraphic->vexs[3].name,"vex3",MAX_STR_LEN);


pGraphic->vexs[4].index = 0;
strncpy(pGraphic->vexs[4].name,"vex4",MAX_STR_LEN);


pGraphic->vexs[5].index = 0;
strncpy(pGraphic->vexs[5].name,"vex5",MAX_STR_LEN);


pGraphic->arcs[0][0].adj = 0;
pGraphic->arcs[0][1].adj = INFINITY;
pGraphic->arcs[0][2].adj = 10;
pGraphic->arcs[0][3].adj = INFINITY;
pGraphic->arcs[0][4].adj = 30;
pGraphic->arcs[0][5].adj = 100;


pGraphic->arcs[1][1].adj = 0;
pGraphic->arcs[1][2].adj = 5;
pGraphic->arcs[1][3].adj = INFINITY;
pGraphic->arcs[1][4].adj = INFINITY;
pGraphic->arcs[1][5].adj = INFINITY;


pGraphic->arcs[2][2].adj = 0;
pGraphic->arcs[2][3].adj = 50;
pGraphic->arcs[2][4].adj = INFINITY;
pGraphic->arcs[2][5].adj = INFINITY;


pGraphic->arcs[3][3].adj = 0;
pGraphic->arcs[3][4].adj = 20;
pGraphic->arcs[3][5].adj = 10;


pGraphic->arcs[4][4].adj = 0;
pGraphic->arcs[4][5].adj = 60;


pGraphic->arcs[5][5].adj = 0;


for(i=0;i<6;i++)
{
for(j=0;j<6;j++)
{
pGraphic->arcs[j][i] = pGraphic->arcs[i][j];
}
}


PrintGraphic(pGraphic);


}


//释放图空间
void DestroyGraphic(Graphic **ppGraphic)
{
NULL_PTR_RET(ppGraphic)


if(NULL != *ppGraphic)
{
free(*ppGraphic);
*ppGraphic = NULL;
}

return ;


}


//打印最短路径
void PrintShortestPath(Graphic *pGraphic,PathFinal *path)
{
int v,w;
NULL_PTR_RET(path)
NULL_PTR_RET(pGraphic)


printf("src:vex[%d]\n",path->v0);
for (v=0; v<pGraphic->vexnum; v++)
{
if(path->P[v][0]<INFINITY)
{ //存在最短路径
printf("dest:vex[%d] :",v);
for (w=0; w<pGraphic->vexnum; w++)
{
if(path->P[v][w]<INFINITY)  
{
printf("%d->",path->P[v][w]);
}
}
printf(" shortest[%d]",path->D[v]);
printf("\n");
}
}
}








/********************************************************************


函数名:shortestPath_DIJ


函数功能:迪杰斯特拉求最短路径


P[v]:按坐标顺序记录路径上的顶点编号,表示从v0到v的最短路径(节点集),p[v][w]表示v0到v路径中,第w个顶点的编号。
D[v]:v0-v的最短路径值
final[v]为TRUE,当且仅当v属于S,即已经求得v0到v的最短路径。为FALSE表示v还属于V集,没有找到最短路径。


严蔚敏书算法,如果v0到v有最短路径v0、vi、vj、vk,则P[v][v0]、P[v][vi]、P[v][vj]、P[v][vk]]、P[v][v]为真,按坐标顺序输出路径时只能列出相应顶点,路径顺序不能保证。
修改严算法,可以得到具体的路径。


入参:Graphic *pGraphic,path->v0


出参:PathFinal *path()


返回值:无


*********************************************************************/


void ShortestPath_DIJ(Graphic *pGraphic, PathFinal *path)
{


    int v,k,i,w,min,final[MAX_VEX_NUM];


/*合法性判断*/
NULL_PTR_RET(pGraphic)
NULL_PTR_RET(path)


/*初始化阶段begin****************************************/


for (v=0; v<pGraphic->vexnum; v++)
{
final[v]=LX_FALSE; 


//权值初始化
path->D[v]=pGraphic->arcs[path->v0][v].adj; // D的初值是v0到其余顶点的直接弧的权值


//路径初始化(设空所有路径)
for(w=0; w<pGraphic->vexnum; w++) 
{
path->P[v][w]=INFINITY;  
}


//第一次求得的v0到其余顶点的最短路径
if (path->D[v]<INFINITY)  

path->P[v][0]=path->v0; //v0到v路径的第0个节点为v0
path->P[v][1]=v;  //v0到v路径的第1个节点初始化为v(后面还会改)
}
}


path->D[path->v0]=0; //v0到v0当然为0
final[path->v0]=LX_TRUE; //初始化,v0属于S集


/*初始化阶段end****************************************/


/*求最短路径begin****************************************/
v=path->v0; //用v记住最近的顶点,初始化为v0


for (i=1; i<pGraphic->vexnum; i++)  //这里循环要从1开始,其余G.vexnum-1个顶点
{  


//直达求最短:从V中选取一个其距离值为最小的顶点W且不在S中,加入S
min=INFINITY;  //min是当前所知离v0顶点的最近距离
for (w=0; w<pGraphic->vexnum; w++) 
{
if (!final[w]) // w顶点在V-S中
{   
if (path->D[w]<min) 

min=path->D[w]; 
v=w; ////w离v0更近,用v记住最近的顶点
}  
}
}
final[v]=LX_TRUE;  //找到最短,将v加入S
//说明:直达的最短不一定是最短,还可能是从S中的顶点转达才最短,下面会再次做比较,这里是提前将final标记置为TRUE。


//非直达求最短:对V中顶点的距离值进行修改,若加进W作中间顶点,从V0到V的距离值比不加W的路径要短,则修改此距离值
for (w=0; w< pGraphic->vexnum; w++) 
{
if (!final[w] && (min + pGraphic->arcs[v][w].adj < path->D[w]))

path->D[w]= min + pGraphic->arcs[v][w].adj;//刷新最短距离


//复制最短路径,此处与严书不同
//初始:p[v]= {v0,....,v,INFINITY,INFINITY,......}
//      p[w]= {INFINITY,....,INFINITY,INFINITY,INFINITY,......}
for(k=0; k<pGraphic->vexnum; k++)

if(path->P[v][k]<INFINITY) 
{
path->P[w][k]=path->P[v][k]; //复制v0-v的路径到v0-w中
//p[w]= {v0,....,v,INFINITY,INFINITY,......}
}
else
{
path->P[w][k]=w;//将w也加入到v0-w中(v到w是直达的) 
//p[w]= {v0,....,v,w,INFINITY,INFINITY,......}
break; //这里必须break
}
}
//最终:p[w]= {v0,....,v,w,INFINITY,INFINITY,......}
}
}
}


    /*求最短路径end****************************************/
}




//测试程序


Graphic *gpGraphic;
PathFinal gPath;


void TestCaseForGraphic()
{
gpGraphic = CreateGraphic();
SetGraphic(gpGraphic);


gPath.v0 = 5;


//求最短路径
ShortestPath_DIJ(gpGraphic,&gPath);


//打印
PrintShortestPath(gpGraphic,&gPath);


DestroyGraphic(&gpGraphic);
}