校园导航系统(Dijkstra算法,含读写.txt类型文件中)

 设计思路 

        设计一个校园交通查询导引系统,能让游客查询学校的全部地点,能够给出各个地点离
当前地点的距离,能够给出从一个地点到另外一个地点的最近距离和路径。同时,该软件还  
具有常用的数据维护功能,例如调研地图信息文件、保存地图、地点添加、道路添加、道路
修改等功能。
        该软件(操作都在终端页面)用到数据结构课程的图、排序、字符串等章节内容。
        这里需要使用到Dijkstra算法求得最短路径
狄克斯特拉 (Dijkstra) 算法
        基本思想是:设 G=(V,E) 是一个带权有向图 , 把图中顶点集合 V 分成两组: 第一组为已求出最短路径的顶点集合( S 表示 , 初始时 S 中只有一个源点 , 以后每求得一 条最短路径 v0, vk, 就将 vk 加入到集合 S , 直到全部顶点都加入到 S , 算法就结束了 ) 第二组为其余未确定最短路径的顶点集合( U 表示 )
        按最短路径长度的递增次序依次把第二组的顶点加入 S 中。在加入的过程中 , 总保持从源点 v0 到 S 中各顶点的最短路径长度不大于从源点 v0 U 中任何顶点的最短路径长度。 此外, 每个顶点对应一个距离 ,S 中的顶点的距离就是从 v0 到此顶点的最短路径长度 ,U 中的顶点的距离从 v0 到此顶点只包括 S 中的顶点为中间顶点的当前最短路径长度。
        狄克斯特拉算法的具体步骤如下:
(1) 初始时 ,S 只包含源点 , S={v0},v0 的距离为 0 U 包含除 v0 外的其他顶点 ,U 中顶点 u 距离为边上的权 ( v0 u 有边 <v0,u>) 或∞。
(2) U 中选取一个距离 v0 最小的顶点 v, v 加入 S ( 该选定的距离就是 v0 v 的最 短路径长度)
(3) v 为新考虑的中间点 , 修改 U 中各顶点的距离:若从源点 v0 到顶点 w(w U) 的距 离( 经过顶点 v) 比原来距离 ( 不经过顶点 v) , 则修改顶点 w 的距离值 , 修改后的距离值为顶点 v 的距离加上边 <v,w> 上的权。
(4) 重复步骤 (2) (3) 直到所有顶点都包含在 S 中。
Dijkstra算法图示如下:
地图数据文件的结构定义
        地图的信息需要保存到一个数据文件中,下图为一个数据文件的例子,在这个例子中,第一
行的 7 代表有 7 个地点,接下来的 7 行为 7 个地点的名称。接下来的 12 代表这个图共有 12 条边,最后的 12 行分别代表这 12 条边,每行的各个数据分别代表起点名称、终点名称、边的长度,边( 道路 ) 名称和边 ( 道路 ) x 轴的夹角。这个数据文件可以通过程序的“保存地图” 菜单得到,也可以用记事本编辑,然后通过程序的“调用地图信息文件”菜单读取到程序中。

在想要读取的路径下创建.txt文件

主要功能:

显示全部景点名称、路程导引、距离最近的景点、地图信息的变更、保存地图、调用地图文件、退出系统。

这里就不展示功能了,直接上代码

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>
#include "iostream"
using namespace std;

#define maxnum 100//最大顶点个数  
#define Yes 1  
#define No 0  
#define INFINITY 999999
int visited[maxnum];  
  
typedef char VertexName[20];//给char[20]数组起别名为Vertex 
  

typedef struct  
{  
	int adj;//相邻与否,或权值大小  
	char name[40];
	int direction;
}Arc;  
  
typedef struct  
{  
	VertexName vexs[maxnum];  
	Arc arcs[maxnum][maxnum];  
	int vexnum,arcnum;  
}LGragh;  

//求顶点位置  
int LocateVex(LGragh *M,VertexName v)  
{  
	int k;  
	for(k=0;k< M->vexnum;k++)  
	{  
		if(!strcmp(M->vexs[k],v)) //strcmp字符串相等返回零 
			return k;  //返回下标 
	}  
	printf("不存在景点%s\n",v);
	return -1;//没有这个顶点  
} 
//加载
void load(LGragh *M)
{
	FILE *fp;
	int i,j,k;
	int weight;
	VertexName v1,v2;  
	fp=fopen("c:\\aaaa\\graph.txt","r");
	
	//得到点的个数  7 
	fscanf(fp,"%d",&M->vexnum);
	
	//初始化矩阵
	for(i=0;i<maxnum;i++)  
		for(j=0;j<maxnum;j++)  
			M->arcs[i][j].adj=INFINITY;
	//得到顶点
	for(i=0;i<M->vexnum;i++) {
		fscanf(fp,"%s",M->vexs[i]);  
	}
	//得到弧数    12
	fscanf(fp,"%d",&M->arcnum);

	fgets(v1,4,fp);
	//初始化弧
	for(k=0;k<M->arcnum;k++)  
	{  
		fscanf(fp,"%s",v1);//从文件中读取
		fscanf(fp,"%s",v2);

		i=LocateVex(M,v1);//查找所在矩阵中的位置  
		j=LocateVex(M,v2);

		fscanf(fp,"%d",&weight);
		fscanf(fp,"%s",&M->arcs[i][j].name);		
		fscanf(fp,"%d",&M->arcs[i][j].direction);

		if(i<0||j<0)
		{ 
			printf("??");
			return;  
		}
		M->arcs[i][j].adj=weight;  
		M->arcs[j][i].adj=M->arcs[i][j].adj;//无向的 
		
		strcpy(M->arcs[j][i].name,M->arcs[i][j].name);

		M->arcs[j][i].direction=(M->arcs[i][j].direction+180)%360;
	}
	fclose(fp);
	return;
}

void Printv(LGragh M)
{
	int i;
	for(i=0;i<M.vexnum;i++)
	{
		cout<<M.vexs[i]<<" ";//循环输出顶点名称,展示所有的景点 
	}
}

//V0初始点,p指针,D存储距离
void Dijkstra(LGragh G, int v0,int P[], int D[])
{
	int v;
	int final[maxnum];
	int min;
	//初始化 
	for(int v=0;v<G.vexnum;v++){
		final[v]=0;
		
		if(G.arcs[v0][v].adj!=0)
			D[v]=G.arcs[v0][v].adj;//存储最短路径 
		else
			D[v]=INFINITY;
			
		if(D[v]<INFINITY)
			P[v]=v0;//存储前驱结点 
		else
			P[v]=-1;
	}
	D[v0]=0;
	final[v0]=1;
	for(int i=1;i<G.vexnum;i++)
	{
		min=INFINITY;
		for(int w=0;w<G.vexnum;w++)
			if(!final[w] && D[w]<min)
			{
				v=w;
				min=D[w];
			}
		final[v]=1;
		for(int w=0;w<G.vexnum;w++)
		{
			if(!final[w] && (min+G.arcs[v][w].adj<D[w]))
			{
				D[w]=min+G.arcs[v][w].adj;
				P[w]=v;
			}
		}
	}
}

void findRoad(char starts[],char ends[],LGragh *M)
{
	
	int p[30],d[30];//路径和距离 
	int path[50];//存储路径顶点 
	int k=0,i;//路径景点计数,循环变量 
	int dir;//存储方向度数变量 
	int temp;
	int start,end;//声明起点和终点 
	start=LocateVex(M,starts);//初始化起点和终点位置 
	end = LocateVex(M,ends);

	if(start==-1||end==-1)//不存在 
		return;

	Dijkstra(*M,start,p,d);//求得最短路径 
	printf("%s---%s 距离为%d\n",M->vexs[start],M->vexs[end],d[end]);
	
	path[k++]=end;//从终点到起点的遍历路径 
	while(p[end]!=-1)//判断是否有前驱结点 
	{
		path[k++]=p[end];//前驱结点添加到路径中 
		end=p[end];//更新end为前驱结点的位置 
	}
	printf("\n");
	for(i=k-1;i>0;i--)
	{
		if(i!=k-1)
		{
			temp=M->arcs[path[i]][path[i-1]].direction-dir;//当前边和前一条边的差值 
			
			if(temp<0)
				temp=360+temp;
			if(temp<45||temp>315)
				printf("向前");
			else if(temp>45 && temp<180)
				printf("向左");
			else
				printf("向右");
		}
		//%s--- %s--- %s
		printf("%s---",M->vexs[path[i]]);// 当前顶点 
		printf("%s---",M->arcs[path[i]][path[i-1]].name);//边名 
		dir = M->arcs[path[i]][path[i-1]].direction;//更新dir为前边,便于下次计算 
		printf("%s\n",M->vexs[path[i-1]]);//结束位置的顶点 
	}
}

void findPoint(char starts[],LGragh *M)
{
	int start;
	int p[30],d[30],i,j,min,k;
	int dir;
	int temp;
	start=LocateVex(M,starts);	
	if(start==-1)
		return;
	Dijkstra(*M,start,p,d);
	for(k=0;k<M->vexnum-1;k++)
	{	
		d[start]=INFINITY;
		min=d[0];j=0;
		for(i = 0; i < M->vexnum; i++)
		{
		   if(d[i]<min)
			{
				min=d[i];
				j=i;
			}
		}
		printf("\n %s 与当点位置的距离为 :%d",M->vexs[j],d[j]);
		d[j]=INFINITY;
	}
}

//添加一个顶点  
void InsertVex(LGragh *G,VertexName v)  
{  
	int i,j;   
	G->vexnum++;   
	strcpy(G->vexs[G->vexnum-1],v);
	i=LocateVex(G,v);  
	for(j=0;j< G->vexnum;j++)
	{  
		G->arcs[i][j].adj=INFINITY;//添加的顶点默认和其他顶点不邻接  
		G->arcs[j][i].adj=INFINITY;  
	}  
}  

//删除一个顶点  
int DeVex(LGragh *G,VertexName v)  
{  
	int i,j;  
	i=LocateVex(G,v);  
	if(i==-1)  
	{  
		printf("点%d不在该图中\n",v);  
		return No;  
	}  
	for(j=0;j< G->vexnum;j++)  
	{  
		G->arcs[i][j].adj=0;  
		G->arcs[j][i].adj=0;//删除与该顶点连接的弧  
	}  
	for(j=i;j<G->vexnum;j++)  
		strcpy(G->vexs[j],G->vexs[j+1]); //空处的位置前移 
	G->vexnum--;  
	printf("删除顶点%s成功!\n",v);  
	return Yes;  
}  
  
//添加一条弧  
int InserArc(LGragh *G)  
{  
	VertexName v1,v2; 
	char name[40];
	int weight;
	int dir;
	int i,j;  
	cout<<"请输入起点名称:"<<endl;
	cin>>v1;
	cout<<"请输入终点名称:"<<endl;
	cin>>v2;
	cout<<"请输入道路名称:"<<endl;
	cin>>name;
	cout<<"请输入距离:"<<endl;
	cin>>weight;
	cout<<"请输入道路方向:"<<endl;
	cin>>dir;
	i=LocateVex(G,v1);  
	j=LocateVex(G,v2);  
	if(i==-1||j==-1)  
	{  
		printf("景点不在图中\n");  
		return No;  
	}  
	G->arcs[i][j].adj=G->arcs[j][i].adj=weight;  
	G->arcs[i][j].direction=dir;

	strcpy(G->arcs[i][j].name,name);
	return Yes;  
}  
 //修改一条弧  
int ChargeArc(LGragh *G)  
{  
	VertexName v1,v2; 
	char name[40];
	int weight;
	int dir;
	int i,j;  
	cout<<"请输入起点名称:"<<endl;
	cin>>v1;
	cout<<"请输入终点名称:"<<endl;
	cin>>v2;
	i=LocateVex(G,v1);  
	j=LocateVex(G,v2);  
	if(i==-1||j==-1)  
	{  
		printf("景点不在图中\n");  
		return No;  
	}  
	cout<<"原来的距离,道路名,方向"<<endl;
	cout<<G->arcs[i][j].adj <<" "<<G->arcs[i][j].name<<" "<<G->arcs[i][j].direction<<endl;

	cout<<"请输入新道路名称:"<<endl;
	cin>>name;
	cout<<"请输入新距离:"<<endl;
	cin>>weight;
	cout<<"请输入新道路方向:"<<endl;
	cin>>dir;

	G->arcs[i][j].adj=G->arcs[j][i].adj=weight;  
	G->arcs[i][j].direction=dir;
	G->arcs[j][i].direction=(dir+180)%360;
	strcpy(G->arcs[i][j].name,name);
	strcpy(G->arcs[j][i].name,name);
	return Yes;  
}  
 
//删除一条弧  
int DeArc(LGragh *G)  
{  
	int i,j;  
	VertexName v1,v2;  
	cout<<"请输入起点名称:"<<endl;
	cin>>v1;
	cout<<"请输入终点名称:"<<endl;
	cin>>v2;
	i=LocateVex(G,v1);  
	j=LocateVex(G,v2); 
	printf("删除成功!\n");  
	if(i==-1||j==-1)  
	{  
	printf("顶点不在该图中\n");  
	return No;  
	}   
	G->arcs[i][j].adj=G->arcs[j][i].adj=INFINITY;  
	return Yes;  
} 

//保 存 地 图
void saveMap(LGragh *M)
{
	int i=0,j;
	FILE *fp = fopen("d:\\a.txt","w"); 
	//向文件写数据
	fprintf(fp,"%d\n",M->vexnum);
	for(i=0;i< M->vexnum;i++)
	{
		fprintf(fp,"\n");
		fputs(M->vexs[i],fp);
	}
	fprintf(fp,"\n");
	fprintf(fp,"%d",M->arcnum);
	for(i=0;i<M->vexnum;i++)
	{
		for(j=i+1;j<M->vexnum;j++)
		{
			if(M->arcs[i][j].adj!=INFINITY)
			{
				fprintf(fp,"\n");
				fputs(M->vexs[i],fp);
				fprintf(fp,"\n");
				fputs(M->vexs[j],fp);
				fprintf(fp,"\n");
				fprintf(fp,"%d",M->arcs[i][j].adj);
				fprintf(fp,"\n");
				fputs(M->arcs[i][j].name,fp);
				fprintf(fp,"\n");
				fprintf(fp,"%d",M->arcs[i][j].direction);
			}
		}
	}
	printf("保存到了d:a.txt文件下");
	fclose(fp);//关闭文件没写 
	return;
}

//调 用 地 图 文 件
void loadN(LGragh *M,char f[20])//参数为结构体和路径长度 
{
	FILE *fp;
	int i,j,k;
	int weight;
	VertexName v1,v2;  
	fp=fopen(f,"r");//对f路径下进行读取 
	 
	//初始化顶点个数
	fscanf(fp,"%d",&M->vexnum);//读取fp下的整数到M->vexnum里 
	
	//初始化矩阵的权值大小 
	for(i=0;i<maxnum;i++)  
		for(j=0;j<maxnum;j++)  
			M->arcs[i][j].adj=INFINITY;
			
	//初始化顶点
	for(i=0;i< M->vexnum;i++) 
		fscanf(fp,"%s",M->vexs[i]);  
		
	//初始化弧的个数
	fscanf(fp,"%d",&M->arcnum);
	
	fgets(v1,4,fp);
	
	//初始化弧
	for(k=0;k< M->arcnum;k++){  
		fscanf(fp,"%s",v1);//从文件中读取两个顶点的名称 例如v0和v1 
		fscanf(fp,"%s",v2);

		i=LocateVex(M,v1);//查找所在矩阵中的位置  
		j=LocateVex(M,v2);
				
		fscanf(fp,"%d",&weight);
		fscanf(fp,"%s",M->arcs[i][j].name);		
		fscanf(fp,"%d",&M->arcs[i][j].direction);

		if(i<0||j<0)
		{ 
			return;  
		}
		
		M->arcs[i][j].adj=weight;  
		M->arcs[j][i].adj=M->arcs[i][j].adj;
		strcpy(M->arcs[j][i].name,M->arcs[i][j].name);
		M->arcs[j][i].direction=(M->arcs[i][j].direction+180)%360;
	}
	fclose(fp);
	printf("加载成功!\n");
	return;
}



///主函数/  
int welcome();
void change(LGragh *M);

int main()  
{  
	LGragh M;  
	int n; 
	char start[20],end[20];
	M.vexnum=M.arcnum=0;  
	load(&M);
	while(n!=7)
	{
		n=welcome();
		switch(n){
			case 1:  Printv(M);  
					 break;
			case 2: 
				cout<<"请输入起点";
				cin>>start;
				cout<<"请输入终点";
				cin>>end;
				getchar();
				findRoad(start,end,&M);  
					 break;
			case 3:
				 Printv(M);
				cout<<"请输入您所在景点";
				cin>>start;
				getchar();
				findPoint(start,&M); 
					 break;
			case 4:
				change(&M); 
					 break;
			case 5:
				saveMap(&M); 
					 break;
			case 6:
				cout<<"请输入完成文件名称(包括盘符与路径)";
				cin>>start;
				loadN(&M,start);
					 break;
			case 7: 
					 break;
		}
		getchar();
	}
}  

int welcome()
{
	int n;
	cout<<"                      旅 游 景 点 引 导 系 统                   "<<endl;
	cout<<"                                                                "<<endl;
	cout<<"    ############################################################"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ##             1. 显 示 全 部 景 点 名 称                 ##"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ##             2. 路 程 导 引                             ##"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ##             3. 离 我 最 近 的 景 点                    ##"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ##             4. 地 图 信 息 变 更                       ##"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ##             5. 保 存 地 图                             ##"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ##             6. 调 用 地 图 文 件                       ##"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ##             7. 退 出 系 统                             ##"<<endl;
	cout<<"    ##                                                        ##"<<endl;
	cout<<"    ############################################################"<<endl;
	cout<<"请输入:";
	cin>>n;
	getchar();
	return n;
}

void change(LGragh *M)
{
	int n,k;
	char v1[20],v2[20];
	cout<<"1. 增加景点"<<endl;
	cout<<"2. 修改景点名称"<<endl;
	cout<<"3. 删除景点"<<endl;
	cout<<"4. 增加道路"<<endl;
	cout<<"5. 修改道路"<<endl;
	cout<<"6. 删除道路"<<endl;
	cout<<"请输入:";
	cin>>n;getchar();
	switch(n)
	{
		case 1: 
			cout<<"请输入景点名称:"<<endl;
			cin>>v1;
			InsertVex(M,v1);
			cout<<"添加景点成功!"<<endl; break;
		case 2:
			cout<<"请输入景点名称:"<<endl;
			cin>>v1;
			cout<<"请输入景点新名称:"<<endl;
			cin>>v2;
			k=LocateVex(M,v1);
			strcpy(M->vexs[k],v2); break;
		case 3:
			cout<<"请输入景点名称:"<<endl;
			cin>>v1;
			DeVex(M,v1); break;
		case 4:
			InserArc(M);break;
		case 5:
			ChargeArc(M);break;
		case 6:
			DeArc(M);break;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值