数据结构课设:(迪杰斯特拉算法求最短路径)校园导航 完整注释

//顶点对最短路径迪杰斯特拉算法 
#include<Windows.h>
#include<string.h>
#include<malloc.h>//malloc()//开辟空间 
#include<limits.h>//INT_MAX,int型最大数 
#include<stdio.h>//EOF(-1),NULL(空0) 
#include<stdlib.h>//atoi();字符串转整形 
#include<io.h>//eof()是否读到文件尾 
#include<math.h>//floor()向下取整,ceil()向上取整,abs()绝对值 
#include<process.h> //exit()退出 
//函数结果代码 
#define TRUE 1
#define FALSE 0
//正确1 
#define OK 1
//错误-1 
#define ERROR -1
//无穷大,设为-1 
#define INFEASIBLE -1
//邻接矩阵和名称数量的最大值 
#define MAXVEX 30
//最大名称字符数量 
#define MAXNAME 20 

//用来记录地点名称 
typedef char VexType[MAXNAME];//顶点名类型(字符串类型) 
//char原本是数组的类型,typedef后,char VexType[MAXNAME]是VexType的类型,Vextype只是一个名称 
typedef int AdjType;//记录是否有边和边的长度
 
 //定义一个图结构 
 typedef struct{
     int n;//图中顶点个数
    VexType vexs[MAXVEX];//顶点信息,记录各个顶点的名字 ,字符串类型,string==vexs 
    AdjType arcs[MAXVEX][MAXVEX];//邻接矩阵,储存边信息,记录顶点与顶点之间的距离 
 }GraphMatrix;
 //想要传入原本数据,需要地址传递 
 //GraphMatrix图结构的别名 
 
 
 typedef struct{//保存最短路径的结构体 
     AdjType len;//从起点到当前节点的最短路径长度
     int pre; //记录当前最短路径的前驱 
 }Path;
 
 
 //遍历查找名为u的在图中的编号
 int locateVex(GraphMatrix *g,VexType u)//图信息是地址传递 
 {
    int i;
    for(i=0;i<g->n;i++){//n个节点,依次遍历 
        if(strcmp(u,g->vexs[i])==0)//strcmp()等于0则意味着找到了该点的编号,编号就是在vexs数组中的位置,即为编号 
        return i;
    } 
    return ERROR;//没找到就返回ERROR 
 }
 
 
 //初始化图的信息 
 void Init(GraphMatrix *g) {
     int i,j,k,w;
     int edgeNums;//所有边的条数
     VexType va,vb;//一条边的两个顶点 
     FILE *graphlist;//文件指针 
     graphlist=fopen("campusnav.txt","r");//打开数据文件,并以graphlist来接受文件的信息 
     
     fscanf(graphlist,"%d",&g->n);//读入所有顶点个数
     fscanf(graphlist,"%d",&edgeNums);//读入所有边的个数
     
     for(i=0;i<g->n;++i)
         fscanf(graphlist,"%s",g->vexs[i]);//所有节点的名字 
    
      for(i=0;i<g->n;i++)//初始化邻接矩阵 
          for(j=0;j<g->n;i++){
          g->arcs[i][j]=INT_MAX;//有权值的网,无路径则置路径为无穷,所以初始化邻接矩阵中每个值都是无穷大 
          }//limits.h头文件内的INT_MAX 
         //先都设为无穷大
          
         
 for(k=0;k<edgeNums;k++){//依次将每个有路径距离的边赋值到初始化图中 
     fscanf(graphlist,"%s%s%d",va,vb,&w);//两点名称,两点之间距离 //读入字符串,不需要&,因为数组名本身就是数组的地址 
     i=LocateVex(g,va);//查两点编号,若没查到,则返回ERROR 
     j=LocateVex(g,vb); 
     if(i!=ERROR&&j!=ERROR){
         g->arcs[i][j]=w;//找到了两点和知道两点间的边后,邻接矩阵内添加从va到vb的距离w 
          
     }else{//若是有一个点或是两个点读取错误,则报错 
         printf("%s<->%s顶点和边的读取错误,请您仔细检查!",va,vb);
         exit(0);//process.h头文件中
        //报错后,直接退出      
     }
 } 
 
 
     for(i=0;i<g->n;i++){ 
     g->arcs[i][i]=0; //各顶点自身到自身的权值为0
     } 
     
     fclose(graphlist);//图的初始化结束,关闭读入的数据文件 
 
}//到此,所有的点和边都以录入完毕

//绘制带权图的邻接矩阵
void printfGraphAdjacencyMatrix(GraphMatrix *g){
    int i,j;
    
    for(i=0;i<g->n;i++){
        for(j=0;j<g->n;j++){
            //遍历整个邻接矩阵
            
            if(g->arcs[i][j]==INT_MAX){//若是邻接矩阵的某条边等于INT_MAX,即该条边不可通,则打印 ∞∞  
                printf(" ∞∞ ");
                
            }else{
                printf("%4d",g->arcs[i][j]);//若是该边有值,可通,则打印距离 
            }
        }
        printf("\n");
    }

//迪杰斯特拉算法,计算两点之间的最短路径
void Dijkstra(GraphMatrix *pgraph,Path dist[],int start){
    //GraphMatrix *pgraph是指向图的指针,即传入一个图结构;
    //Path dist[]保存从起始点到下标所在该点最短路径信息的数组;
    //int start 起始顶点编号 
    int i,j,min;
    AdjType minw;//所在最小边长 
    dist[start].len=0;//将起始点到起始点的最短路径长度dist[start].len设置为0
    dist[start].pre=0;//前驱顶点编号dist[start].pre也设置为0;
    pgraph->arcs[start][start]=1;//表示顶点start以及已经加入集合U中,集合U(表示已经找到最短路径的顶点集合)即记录是否找到过该点,并且到自身的距离为1表示已经找过该点 
    for(i=0;i<pgraph->n;i++){//对集合V-U中的每个顶点i,初始化其到起始顶点start的距离为边的权值
     
        dist[i].len=pgraph->arcs[start][i];//初始距离为起点到各个顶点的边的权值,有边的记录边的距离,无边的记录INT_MAX 
        
        if(dist[i].len!=INT_MAX)//若边存在则顶点i的当前前驱顶点设为start,不存在则置为-1,表示不存在 
         dist[i].pre=start;//存在从start直接到i的路径 
         else 
         dist[i].pre=-1;//不存在从start直接到i点,前驱为-1表示不存在 
         
    }
     
    dist[start].pre=-1;//起点的前驱节点也置为-1;
    
    //在集合V-U中选出距离值最小的顶点,将前驱置为已经加入集合U,同时调整集合V-U中其他顶点的最短路径
    for(i=0;i<pgraph->n;i++){//循环遍历集合V-U中的每个顶点;
    minw=INT_MAX;//最小权重minw初始化为最大整数INT_MAX,从大开始比较,最后得到当前最短边的值
     
    min=start;//将当前顶点设置为起始顶点start
    for(j=0;j<pgraph->n;j++){//遍历集合V-U中的每个顶点j
        if((pgraph->arcs[j][j]==0)&&(dist[j].len<minw))//在V-U中选出距离值最小顶点,自身到自身的距离用来记录是否访问过 
        {
        minw=dist[j].len;
         min=j;//最后min为当前距离最短的点; 
         } //判断顶点j是否属于集合V-U(==0就是没加入),以及到起始顶点的距离是否小于当前最小权重
         printf("%d %d\n",minw,min); }
        if(min==0)//没有路可以通往任何顶点
        break;
        
        pgraph->arcs[min][min]=1;//路径最小的顶点设为min,置为已访问状态 
        
        for(j=0;j<pgraph->n;j++){//遍历集合V-U中的每个顶点j,调整其最短路径 
            if(pgraph->arcs[j][j]==1)//该顶点已经并入,已访问过,不用再考虑
            continue;
            
            printf("%d %d %d\n",dist[j].len,dist[min].len,pgraph->arcs[min][j]);
            if(dist[j].len>dist[min].len+pgraph->arcs[min][j]&&dist[min].len+pgraph->arcs[min][j]>0)
            //如果满足条件,使用当前的最小顶点来更新顶点j的最短路径信息
            //dist[j].len>dist[min].len+pgraph->arcs[min][j]表示通过最小顶点min的路径会得到更短的最短路径。
            //dist[min].len+pgraph->arcs[min][j]>0表示更新后的最短路径存在。
            {
                dist[j].len=dist[min].len+pgraph->arcs[min][j];//更新顶点j的最短路径
                dist[j].pre=min;//更新前驱节点; 
            }
          }             
         
    }     
        
    } 
 
 
 int main(int argc,char* argv[]){
     
     system("color 3c");//控制台屏幕变蓝

     GraphMatrix graph;//定义一个图 
     Path path[MAXVEX];//用于记录最短路径 
     int tmp,cnt=0,pre=-1; 
     int temppath[MAXVEX]; //去除最短路径所经过的节点 
     int m,n;
     VexType va,vb;//待查询的两个地点
     long totallen=0;//总路径长度
     long curlen=0;//当前路径长度
     Init(&graph);
     printf("查找一下地点路径: \n");
     int i;
     for(i=0;i<graph.n;++i)//输出所有顶点名称 
     printf("%s",graph.vexs[i]);
     
     printf("\n");
     printf("\n邻接矩阵: \n");
     
     printGraphAdjacencyMatrix(&graph);//输出邻接矩阵 
     printf("\n输入起点和终点\n");
     scanf("%s%s",va,vb);//输入两点 
     m=LocateVex(&graph,va);//找到两点编号 
     n=LocateVex(&graph,vb);
     if(m!=ERROR&&n!=ERROR){//两个顶点都在图中,则找出二者间最短路径可输出 
         Dijkstra(&graph,path,m);//迪杰斯特拉算法求最短路径 
         //因为求得的路径上顶点是从终点推到起点,现在将之逆置
         for(tmp=0;tmp<MAXVEX;tmp++)
             temppath[tmp]=-1;//temopath数组初始化为-1 
             
             pre=n;//最后位置到达的点位 
             while(path[pre].pre!=-1){//向前追溯最短路径经过的节点
              
                 temppath[cnt]=pre;
                 pre=path[pre].pre; 
                 cnt++;
             }
             temppath[cnt]=m;//当检测到path[pre].pre!=-1时,退出,最后一个前驱没有记录,退出后再录入 
             if(cnt<=0)//cnt<=0表明没有经历cnt,即没有路径
                 if(m!=n)
                 printf("%s->%s这之间没有通路\n",graph.vexs[m],graph.vexs[n]);
                 else
                 printf("输入的起点与终点有重合!\n");
            else
            {
                tmp=cnt;
                printf("%s到",graph.vexs[temppath[tmp]]);
                for(;tmp>0;tmp--){
                    printf("%s(%d)到",graph.vexs[temppath[tmp-1]],graph.arcs[temppath[tmp]][temppath[tmp-1]]);
                    totallen+=graph.arcs[temppath[tmp]][temppath[tmp-1]];
                    }
            ; 
     } 

printf("距离共:%d米\n",totallen);
     
      
 }
 else
 printf("(%s<->%s)输入的地点有不存在的地方,请您仔细检查!!",va,vb);
 return 0;
 

 迪杰斯特拉算法是,现以起始点更新每个点的最短路径,找每个没有访问并最短路径最短的点,更新最短点附近所有连接的点的最短路径,直到所有的点都标记为已访问为止,每次更新最短路径都要把他的前驱更新一下,如此便可追溯两点间的路径

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值