数据结构之最短路径

数据结构之最短路径
目 录

一.概述…1
二.设计目的…1
三.详细设计…2
3.1问题描述…2
3.2功能需求…2
3.3实现要点…2
3.4图的存储结…3
3.5单源最短路径…3
四.源程序代码…4
五.运行与测试…4
六.总结与收获…16
七.参考文献…16

甘肃农业大学景点咨询系统设计(最短路径问题)
一.概述
在交通网络日益发达的今天,针对人们关心的各种问题,尤其是在大学里,怎么才能用最少的时间达到最高的效率,对每一个学生来说都是至关重要的。所以利用计算机建立一个交通咨询系统。在系统中采用图来构造各个教学楼及其宿舍食堂之间的联系,图中顶点表示地点,边表示各个地点之间的距离,所带权值为两个地点之间的耗时长度,这个交通咨询系统可以回答学生提出的各种问题,例如:如何选择一条路径使得从A楼到B楼途中中转次数最少;如何选择一条路径使得从A楼到B楼里程最短;如何选择一条路径使得从A楼到B楼用时最少等等的一系列问题。设计一个交通咨询系统,能咨询从任何一个顶点到另一顶点之间的最短路径里程、最少时间等问题。对于不同的咨询要求,可输入两点间的路程、所需时间等信息。
针对最短路径问题,在本系统中采用图的相关知识,以解决在实际情况中的最短路径问题,本系统中包括了建立图的存储结构、单源最短问题,增设景点本系统还设置了提示菜单,方便使用者使用。

二.设计目的
1.了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;
2.初步掌握软件开发过程的向题分析、系统设计、程序编码、测试等基本方法和技能;
3.提高综合运用所学的理论知识和方法独立分析和解决问题的能力;
4.训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所具备的科学工作方法;

三.详细设计
3.1问题描述
图的最短路径问题是指从指定的某一点v开始,求得从该地点到图中其它各地点的最短路径,并且给出求得的最短路径的长度及途径的地点。除了完成最短路径的求解外,还能对该图进行修改,如顶点的增加和删除、修改等。校园最短路径问题中的数据元素有:
a)顶点数
b)两点之间的距离
3.2功能需求
要求完成以下功能
1.显示景点地图。
2.文件的读取与保存
3.遍历景点。
4.修改:修改两个位置的距离,并重新录入每两个位置的距离。
5.求最短路径:输出给定两点之间的最短路径的长度。
6.删除:删除任意两点之间的距离,即此两点之间无法直接到达。
7.任意两点之间的最短路径
3.3实现要点
1.对图的创建采用邻接矩阵的存储结构,而且对图的操作设计成了模板类。
2.用户可以先录入所有的地点的名称和编号。
3.用户可以随意修改两点之间的距离。
4.用户可以增加顶点的个数及删除两点之间的距离。
5.当用户操作错误时,系统会出现出错提示。、

3.4图的存储结构
typedef struct//定义对各个景点信息存储的结构体类型
{
int top;//景点序号
char info[maxsize];//景点名称
char introduce[maxsize];//景点介绍
} data;//定义顶点类型
typedef struct node
{
int adj;//相邻接的景点间的距离
} node;//定义边的类型
typedef struct
{
data vertex[maxsize];//景点、顶点
node arcs[maxsize][maxsize];//景点间距离
int vexnum,arcnum;//景点数、边数
}AdjMatrix;//定义图的类型
3.5单源最短路径
Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)
从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

四.源程序代码
map.c

#include"map.h"
/*校园地图*/
void Seen()
{
    system ("color 0b");
    printf("------------------------**** 甘肃农业校园平面图****----------------------    \n\n");
    printf(" 篮球场----学生公寓                                                           \n\n");
    printf(" |              |    ╲                                                        \n\n");
    printf(" |              |        ╲                                                    \n\n");
    printf(" |              |            ╲                                                 \n\n");
    printf(" |              |                ╲                                            \n\n");
    printf(" |              |            ╱  二号食堂-----------小树林---------    图书馆 \n\n");
    printf(" |              |        ╱             |             /                     |   \n\n");
    printf(" 四号教学楼----认知馆                   |           /                       |  \n\n");
    printf(" |            /  |   ╲                 |          /                        |       \n\n");
    printf(" |           /   |     ╲               |        /                          |       \n\n");
    printf(" |         /     |           ╲         |      /                            |       \n\n");
    printf(" |       /       |                 ╲   |    /                              |         \n\n");
    printf(" |      /        |                      体育馆                       逸夫科技馆    \n\n");
    printf(" |     /         |                          ╲                       /       |         \n\n");
    printf(" |    /          |                             ╲                  /         |         \n\n");
    printf(" 西大门------葡萄园                               ╲            /            |        \n\n ");
    printf("                                                     动物医院 ------------ 伏羲堂      \n\n");
    printf("                                                            ╲               |        \n\n");
    printf("                                                               ╲            |        \n\n");
    printf("                                                                  ╲         |        \n\n");
    printf("                                                                    ╲       |        \n\n"); 
    printf("                                                                      ╲     |        \n\n"); 
	printf("                                                                          南门        \n\n");
    
}
 
/*已存景点阅览*/
void PlaceList()
{
    system ("color 0b");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃                     **已有景点 **                ┃\n");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃  1.南大门               ┃2.伏羲堂               ┃\n");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃  3.逸夫科技馆          ┃4.小树林                ┃\n");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃  5.小树林             ┃6.动物医院               ┃\n");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃7.体育馆               ┃8. 二号食堂             ┃\n");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃9.学生公寓                ┃10.篮球场             ┃\n");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃11.四号教学楼             ┃12.认知馆             ┃\n");
    printf("\t\t┏**************************************************┓\n");
    printf("\t\t┃13.葡萄园                ┃14.西大门              ┃\n");
    printf("\t\t┏**************************************************┓\n");
}
 
/*访问标志数组初始化*/
void creatvisited(AdjMatrix *g)
{
    int i;
    for(i=0; i<g->vexnum; i++)
        visited[i]=0;
} 
/*遍历*/
void search(AdjMatrix *g)
{
    int i,n;
    creatvisited(g);
    for(i=0; i<g->vexnum; i++)
        printf("%d\t%s\n",g->vertex[i].top,g->vertex[i].info);
    printf("请输入遍历的起点序号:(1-%d)\n",g->vexnum);
    scanf("%d",&n);
    DFS(g,n-1);
}
 
/*深度遍历*/
void DFS(AdjMatrix *g,int v)
{
    int k;
    visited[v]=1;//置已访问标记
    printf("景点序号:%d 名称:%s\n",g->vertex[v].top,g->vertex[v].info);
    for(k=0; k<g->vexnum; k++)
        if(!visited[k]&&g->arcs[v][k].adj!=INF)
            DFS(g,k);
}
/*已存景点信息文本*/
void f_vernum(AdjMatrix *g)
{
    FILE *fp;
    int i;
    fp=fopen("vernum.txt","wb");
    for(i=0; i<g->vexnum; i++)
        fprintf(fp,"%d %s %s\n",g->vertex[i].top,g->vertex[i].info,g->vertex[i].introduce);
    fclose(fp);
}
 
/*已存景点间路径文本*/
void f_arcnum(AdjMatrix *g)
{
    FILE *fp;
    int i,j;
    fp=fopen("arcnum.txt","wb");
    for(i=0; i<g->arcnum; i++)
        for(j=0; j<g->arcnum; j++)
            if(g->arcs[i][j].adj!=INF)
            {
                fprintf(fp,"%d %d %d\n",g->vertex[i].top,g->vertex[j].top,g->arcs[i][j].adj);
            }
    fclose(fp);
}
/*读取景点信息*/
void read_vernum(AdjMatrix *g)
{
    FILE *fp;
    int i=0;
    fp=fopen("vernum.txt","rt");
    while(fscanf(fp,"%d %s %s",&g->vertex[i].top,g->vertex[i].info,g->vertex[i].introduce)!=EOF)
    {
        printf("景点序号:%d 名称:%s\n",g->vertex[i].top,g->vertex[i].info);
        printf("景点信息:%s\n",g->vertex[i].introduce);
        printf("\n");
        i++;
    }
    g->vexnum=i;
    fclose(fp);
}
/*读取路径信息*/
void read_arcnum(AdjMatrix *g)
{
    FILE *fp;
    int i=0,j=0,k=0;
    for(i = 0; i<g->vexnum; i++)
        for(j = 0; j<g->vexnum; j++)
            g->arcs[i][j].adj =INF;
    fp=fopen("arcnum.txt","rt");
    while(fscanf(fp,"%d %d %d",&i,&j,&k)!=EOF)
    {
        g->arcs[i-1][j-1].adj=k;
    }
    fclose(fp);
}
/*  读取景点信息*/
void findvernum(AdjMatrix *g)
{
    int i,n;
    char choice;
    for(i=0; i<g->vexnum; i++)
        printf("%d\t%s\n",g->vertex[i].top,g->vertex[i].info);
    do
    {
        printf("请输入要查询的景点序号(1-%d):\n",g->vexnum);
        scanf("%d",&n);
        printf("景点名称:%s\n",g->vertex[n-1].info);
        printf("景点信息:%s\n",g->vertex[n-1].introduce);
        printf("\n");
        printf("是否继续查询:(y/n):\n");
        _flushall();
        scanf("%c",&choice);
    }
    while(choice=='Y'||choice=='y');
}
 
/*弗洛伊德算法*/
void floyd(AdjMatrix *g)
{
    int i,j,k;
    for(i=0; i<g->vexnum; i++)
        for(j=0; j<g->vexnum; j++)
            shortest[i][j]=0;
    for(i=0; i<g->vexnum; i++)
        for(j=0; j<g->vexnum; j++)
        {
            shortest[i][j]=g->arcs[i][j].adj;
            path[i][j]=0;
        }
    for(i=0; i<g->vexnum; i++)
        for(j=0; j<g->vexnum; j++)
            for(k=0; k<g->vexnum; k++)
                if(shortest[i][j]>(shortest[i][k]+shortest[k][j]))
                {
                    shortest[i][j]=shortest[i][k]+shortest[k][j];
                    path[i][j]=k;
                    path[j][i]=k;
                }
}
 
/*最短路径*/
void shortload(AdjMatrix *g)
{
     int i,j,a,b;
     PlaceList();
     floyd(g);
     printf("请输入起始景点和终止景点(1-%d):\n",g->vexnum);
     scanf("%d%d",&i,&j);
     a=i;
     b=j;
     i=i-1;
     j=j-1;
     if(i<j)
	 {
        printf("%d",b);
        while(path[i][j]!=0)
		{
            printf("<-%d",path[i][j]+1);
            if(i<j)
                j=path[i][j];
            else
                i=path[j][i];
		}
     printf("<-%d",a);
     printf("\n\n");
      printf("%d->%d 距离是:%d米\n\n",a,b,shortest[a-1][b-1]);
      
	 }
    else
	{
       printf("%d",a);
       while(path[i][j]!=0)
	   {
           printf("<-%d",path[i][j]+1);
           if(i<j)
            j=path[i][j];
            else
            i=path[j][i];
	   }
        printf("<-%d",b);
         printf("\n\n");
         printf("%d->%d 最短距离是:%d米\n\n",a,b,shortest[a-1][b-1]);
	}
}
void  add_top(AdjMatrix *g)
{
	int i,n;
    char choice;
	FILE *fp;
    fp=fopen("vernum.txt","a");
    printf("\n\n");
    do
    { 
        printf("\t\t请输入增加的地点编号、地点信息,地点简介:");
        scanf("%d%s%s\n",&g->vertex[i].top,g->vertex[i].info,g->vertex[i].introduce);
        fprintf(fp,"%d%s\n",g->vertex[i].top,g->vertex[i].info);
        fprintf(fp,"%s\n",g->vertex[i].introduce);
        printf("是否继续输入?(y/n)\n");
        printf("\n");
        _flushall();
        scanf("%c",&choice);
    } while(choice=='Y'||choice=='y'); 
    fclose(fp);
    printf("\n\t\t按任意键进入下一步...");
    getch();
}
//增加路径 
void add_arc(AdjMatrix *g)  
{  
    int v1, v2, n;
	 FILE *fp;
    fp=fopen("arcnum.txt","a");
    system("cls");
    printf("请输入你想增加的边两端的顶点序号:\n");  
    printf("请输入第一个顶点号:\n");  
    scanf("%d",&v1);  
    printf("请输入第二个顶点号:\n");  
    scanf("%d",&v2); 
    if(g->arcs[v1][v2].adj==INF)  
    {  
        printf("请输入两点之间的距离:\n");  
        scanf("%d",&g->arcs[v1][v2].adj);  
        g->arcs[v2][v1].adj=g->arcs[v1][v2].adj; 
	    g->arcnum ++;
        fprintf(fp,"%d %d",g->vexnum,g->arcnum);   
        printf("增加成功!\n"); 
		fprintf(fp,"%10d%10d%10d\n",v1,v2,g->arcs[v1][v2].adj); 
    }  
    else  
    {  
        printf("这两点已经有路径存在了,你想要修改它吗?想的话请按1,不想请按2:\n");  
        scanf("%d",&n);  
        if(n==1)  
        {  
            printf("请输入两点之间的新的距离:\n");  
            scanf("%d",&g->arcs[v1][v2].adj);  
            g->arcs[v2][v1].adj=g->arcs[v1][v2].adj;  
            printf("修改成功!\n");
        }  
        else if(n==2)  
        {  
            printf("增加失败,呜呜呜T_T\n");  
        }  
        else  
        {  
            printf("你的输入有误,请重新输入!\n");  
            return;  
        }  
    
    fprintf(fp,"%10d%10d%10d\n",v1,v2,g->arcs[v1][v2].adj);
    fclose(fp);
    printf("\n\t\t按任意键进入下一步...");
    getch();
} 
}
//删除路径  
void delete_arc(AdjMatrix *g)  
{  
    int v1, v2;
	 FILE *fp;
        fp=fopen("arcnum.txt","a");
    system("cls");
    printf("\n\n");
    do{
        printf("\t\t请输入删除路线的起点建筑:");
        scanf("%d",&v1);
    }while(v1<=0 || v1>g->vexnum);
    do{
        printf("\t\t请输入删除路线的终点建筑:");
        scanf("%d",&v2);
    }while(v2<=0 || v2>g->vexnum);
    if(g->arcs[v1][v2].adj!= INF) {  //如果以前有这条弧
        g->arcs[v1][v2].adj= INF;
        g->arcs[v2][v1].adj = INF;  //则将矩阵元素赋值为无穷,表示没有这条弧了
        g->arcnum --;     //并将图的边数-1
        fputc('\n',fp);
        fprintf(fp,"%10d%10d%10d",v1,v2,g->arcs[v1][v2]);
        fclose(fp);
        printf("\n\t\t这条路线删除成功~!\n");
    }
    else {
        printf("\n\t\t这条路线不存在\n");
    }
    printf("\n\t\t按任意键返回...");
    getch();
}  
 
/*菜单栏*/
int meun()
{   system("color 0b"); 
    system("cls");
    char choice;
    AdjMatrix  *g;
    g=(AdjMatrix  *)malloc(sizeof(AdjMatrix));//创建头结点
    while(1)
    {   
        printf("\n");
        printf("\t\t---------------------------*******-----------------------------\n");
        printf("\t\t------------------***甘肃农工大学校园景点导航系统**-------------\n");
        printf("\t\t------------------******谢谢使用~~*******----------------------------\n");
        printf("\t\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("\t\t**~~~~~~~~~~~~~~~\t 1: 查看景点地图**~~~~~~~~~~~~~~~~~~~~\n");
        printf("\t\t**~~~~~~~~~~~~~~~\t 2: 读取文件信息~~~~~~~~~~~~~~~~~~~~**\n");
        printf("\t\t**~~~~~~~~~~~~~~~\t 3: 遍历景点信息~~~~~~~~~~~~~~~~~~~~~~~~**\n");
        printf("\t\t**~~~~~~~~~~~~~~~\t 4: 查询景点信息~~~~~~~~~~~~~~~~~~~~~~~~**\n");
        printf("\t\t**~~~~~~~~~~~~~~~\t 5: 查询最短路径~~~~~~~~~~~~~~~~~~~~~~~~**\n");
        printf("\t\t**~~~~~~~~~~~~~~~\t 6: 增加新景点~~~~~~~~~~~~~~~~~~~~~~~~~~**\n");
        printf("\t\t**~~~~~~~~~~~~~~~\t 7: 增加路径~~~~~~~~~~~~~~~~~~~~~~~~~~~~**\n");
        printf("\t\t**~~~~~~~~~~~~~~~\t 8: 删除路径~~~~~~~~~~~~~~~~~~~~~~~~~~~~**\n");      
        printf("\t\t**~~~~~~~~~~~~~~~\t 0: 退出查询系统~~~~~~~~~~~~~~~~~~~~~~~~**\n");
        printf("\t\t---------------------------*******-----------------------------\n");
         printf("\t\t---------------------------*******-----------------------------\n");
        printf("\n");
        printf("请选择使用的功能序号:");
        choice=getchar();
        switch(choice)
        {
        case '1':
        {
            Seen(g);
            break;
        }
        case '2':
        {
            read_vernum(g);
            read_arcnum(g);
            break;
        }
        case '3':
        {
            search(g);
            break;
        }
        case '4':
        {
            findvernum(g);
            break;
        }
        case '5':
        {
            shortload(g);
            break;
        }
         case '6':
        {
            add_top(g);
            break;
        }
         case '7':
        {
            add_arc(g); 
            break;
        }
         case '8':
        {
            delete_arc(g);
            break;
        }
        
    
        case '0':
        {
            printf("感谢您的使用!\n");
            exit(0);
        }
        }
        printf("请按任意键继续.....");
        getch();
        _flushall();//清除缓存区 
        system("cls");
    }
}

map.h

#include<stdio.h>
#include<stdlib.h>//调用system函数
#include<conio.h>
#include<string.h>
#include<windows.h>
#define maxsize 1000
#define INF 100000//两景点不可到距离长度
int visited[maxsize];//全局变量
int path[maxsize][maxsize];//经过景点
int shortest[maxsize][maxsize];//最短路径
typedef struct//定义对各个景点信息存储的结构体类型
{
    int top;//景点序号
    char info[maxsize];//景点名称
    char introduce[maxsize];//景点介绍
} data;//定义顶点类型
typedef struct node
{
    int adj;//相邻接的景点间的距离
} node;//定义边的类型
typedef struct
{
    data vertex[maxsize];//景点、顶点
    node arcs[maxsize][maxsize];//景点间距离
    int vexnum,arcnum;//景点数、边数
}AdjMatrix;//定义图的类型
 
void Seen();/*校园地图*/
void PlaceList();/*已存景点阅览*/
void creatvisit(AdjMatrix *g);/*访问标志数组初始化*/
void DFS(AdjMatrix *g,int v);/*深度遍历*/
void search(AdjMatrix *g);/*遍历*/
void f_vernum(AdjMatrix *g);/*已存景点信息文本*/
void f_arcnum(AdjMatrix *g);/*已存景点间路径文本*/
void read_vernum(AdjMatrix *g);/*读取景点信息*/
void read_arcnum(AdjMatrix *g);/*读取路径信息*/
void findvernum(AdjMatrix *g);/*查询景点信息*/
void floyd(AdjMatrix *g);/*弗洛伊德算法*/
void shortload(AdjMatrix *g);/*最短路径*/
void  add_top(AdjMatrix *g);//增加顶点 
void  add_arc(AdjMatrix *g);//增加 路径 
void  delete_arc(AdjMatrix *g);//删除路径 
int meun();/*菜单栏*/

main.c

#include"map.c"
/*主函数*/
int main()
{ 
    meun();
    return 0; 
}

arcnum.txt

1              6                273
2              3                205
2              6                211
3              4                151
3              6                328
4              5                200
5              8                220
5              7                210
7              8                93
6              7                330
12            7                384
12            8                471
12            11               136
14            11                203
12             13               198
14            13                 96
10             11               375
10              9                100
9                12              360
9                8                200

在这里插入代码片

vernum.txt

1.南门       甘肃农业大学南大门
2.伏羲堂        该楼为学校标志性建筑,自建校起即有。为第一任校长盛彤笙亲自所起,并于2010年重修,现为综合性实验楼
3.逸夫科技馆    带你体验不一样的科技之旅
4.图书馆        藏书浩如烟海,让你沉浸在知识的海洋  
5.小树林     风景秀丽,鸟语花香,是约会看书的好地方哟!
6.动物医院     如果你的小宠物生病了,可以去这里哦
7.体育馆      强健体魄,全面发展
8.二号食堂    本学校最好吃的食堂
9.学生公寓       当然是住宿的地方啦
10.篮球场      喜欢篮球的可以考虑多去去
11.四号教学楼        上课的地方
12.认知馆     本校的校史,人类的发展史等等都可以在里面看到
13.葡萄园     种植葡萄的的地方,酿之成美酒,令人饮不足
14.西大门    甘肃农业大学西大门
17小西湖


五.运行与测试

六.收获与总结
该课程设计主要是从日常生活中经常遇到的交通网络问题入手进而利用计算机去建立一个交通咨询系统,以处理和解决学生们关心的各种问题(当然此次试验最终主要解决的问题是:最短路径问题)这次试验中我深刻的了解到了图在计算机中的应用,对于很多的问题我们可以通过图的相关知识来解决,特别是在解决最短路径问题中,显得尤为重要。经过着次实验,我了解到了关于图的有关算法,对图的学习有了一个更深的了解。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值