基于Dijkstra算法的校园导游咨询(C++)

这里附上该设计的源码(.cpp文件)和课程实验报告链接,免费下载!!!

https://download.csdn.net/download/qq_51187087/84121592

一、实验内容

【问题描述】

(1)设计济南大学的校园导游图,所含景点不少于10个。以图中顶点表示学校各景点,存放景点名      称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。

(2)为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。

(3)校园导游图可以根据需要随时增加景点和道路。

(4)可以求出任意两个景点之间的所有路径。

(5)多个景点的最佳访问路线查询,即经过这多个景点的最短路径。

(6)为来访客人提供图中任意景点相关信息的查询。

【测试数据】

根据济南大学校园内的实际情况自己定义一个校园平面图。

【实现提示】

一般情况下,校园的道路是双向通行的,可设校园平面图是无向图。用Dijkstra算法计算最短路径。

目录

一、实验内容

二、数据结构设计

三、代码实现

四、程序运行情况

1、主页面

2、功能页面

3、查询景点信息

 4、查询两景点的最短路径及最短路径长度

5、查询景点的最佳路径及路径长度

 6、添加景点

五、评价


二、数据结构设计

        校园的道路是双向通行的,可设校园平面图是无向图。定义一个邻接矩阵的Graph类,该类中有构造函数,析构函数。为了实现相应功能加入的函数如下:

ShortestPath(int v)函数用于查找两点间的最短路径。

FindAllPath(int **Array,Node startNodeKey,Node endNodeKey)函数用于查找两点间的所有路径。

FindManyPath(int v,int x)用于查找多个景点的最佳路径。

Increase()函数用于插入景点和道路。

search()函数用于查找景点的信息。

ver结点用来保存相关景点的信息code保存景点代码,name保存景点名称,intro保存景点简介Node结点用来在查找两点间所有路径时key记录顶点序号,flag记录该顶点是否已经遍历过。

三、代码实现

话不多说,直接上代码。

/*
	参考文献:殷人昆《数据结构(用面向对象方法与C++语言描述)(第2版)》,
	版次:2007年6月第2版
	页码:PP376-379
	编译环境:vs2019
	编辑日期:2020年12月24日
	调试实现:夏洛克
*/
#include <iostream>
#include <string>
#include <iomanip>
#include <stack>
using namespace std;
 
const int maxValue=9999;
const int maxVertices = 100;						// 最大顶点数
const int DefaultVertices = 20;	                    // 默认顶点数
const int num=20;

struct ver                                          //顶点的结构体 
{
	char code;
	string name;
	string intro;
};
     
struct Node                                       //
{  
    int key;  
    int flag;  
    Node()  
    {  
        flag=0;  
    }  
};

class Graph                                                          //图的邻接矩阵类定义
{
public:
	Graph ();										                 // 构造函数
	~Graph();										                 // 析构函数
	int NumberOfVertices();                                          // 返回当前顶点数
	int NumberOfEdges();                                             // 返回当前边数
	ver getValue (int i);						                     // 取顶点 i 的值
	int getWeight (int v1, int v2);					                 // 取边上权值
	int getVertexPos (char code);					                 // 给出顶点代码code在图中位置
	bool insertVertex (char code,string name,string intro);		     // 插入一个顶点vertex
	bool insertEdge (int v1, int v2, int cost);		                 // 插入边(v1, v2), 权为cost
	void Seek(int i);                                                // 输出顶点i的信息
	void ShortestPath(int v);                                        // Dijkstra求最短路径算法
	void CoutShortest(int v,int x);                                  // 输出两顶点间的最短路径和距离
	void FindAllPath(int **Array,Node startNodeKey,Node endNodeKey); // 查找两点间的所有路径
	void CoutAllPath(int v1,int v2);                                 // 输出两顶点间的所有路径
	int FindManyPath(int v,int x);                                   // 查找多个顶点间的最佳路径 
	void CoutMany();                                                 // 输出多个顶点间的最佳路径
	void Increase();                                                 // 增加景点和道路 
	int **Edg(){return Edges;};										 // 返回邻接矩阵
	void search();                                                   // 景点信息查询 
	void shorest();                                                  // 查询两景点间最短距离
	void allpath();                                                  // 查询任意两景点间的所有路径
	void Map();	                                                     // 动态生成景点列表 
private:
	int maxVertices;	            // 图中最大顶点数
	int numEdges;		            // 当前边数
	int numVertices;	            // 当前顶点数
	ver * VerticesList;				// 顶点表 (各边链表的头结点)
	int **Edges;					// 邻接矩阵保存边
	int *path;                      // 保存该结点的前一个结点
	int *dist;                      // 保存路径长度
	int resultPath[num][num];       // 保存该结点的前一个结点
	int result[num+1];              // 保存结果集
    bool Mark[num];                 // 标记结点
    int pathNum;                    // 两点间所有路径的数目
	int nPos;                       // 栈中的顶点数	
};

// 构造函数
Graph::Graph() 
{
	maxVertices = DefaultVertices;	                    // 初始化 最大顶点数 
	numVertices = 0;				                    // 初始化 顶点个数 
	numEdges = 0;					                    // 初始化 边数 
	VerticesList = new ver[maxVertices];				// 创建顶点表数组
	Edges = (int **) new int*[maxVertices];             // 创建邻接矩阵数组
	for (int i = 0; i<maxVertices; i++)
		Edges[i] = new int[maxVertices];
	for (int i = 0; i<maxVertices; i++)
		for (int j = 0; j<maxVertices; j++)
			Edges[i][j] = (i==j)?0:maxValue;		    // 邻接矩阵主对角线元素为0;顶点对间无边则权重无穷大
	insertVertex('a',"校门","该门为正门,也叫南门");
	insertVertex('b',"升华广场","中央矗立着显眼的升华雕像,象征着济大学子茁壮成长。");
	insertVertex('c',"图书馆","藏书众多,供学生阅览。");
	insertVertex('d',"第十二教学楼","信息科学与工程学院是济南大学主要二级学院之一。");
	insertVertex('e',"白鹭园","绿水青山,白鹭为伴,诗般的意境。");
	insertVertex('f',"牡丹园","院内牡丹娇艳绽放,景色宜人。");
	insertVertex('g',"第十一教学楼","该教学楼分为六段,是主要的教学基地。");
	insertVertex('h',"滋兰苑","UJN图标尤为显眼,济南大学的“大花园”。");
	insertVertex('i',"齐园","内有稷下衢廊,是休息的好地方。");
	insertVertex('j',"校庆景观","济南大学七十周年标示。");
	insertVertex('k',"逸夫楼","是智能材料与工程研究基地。");
	insertEdge(0,1,100);
	insertEdge(1,2,100); 
	insertEdge(2,3,100);
	insertEdge(2,9,800);
	insertEdge(3,4,100); 
	insertEdge(3,5,200);
	insertEdge(4,6,200);
	insertEdge(5,6,300);
	insertEdge(6,7,400);
	insertEdge(7,8,300);
	insertEdge(9,10,500);      
};

//析构函数
Graph::~Graph()
{
	delete[] VerticesList;
	delete[] Edges;
	delete[] path;
	delete[] dist;
};

//返回当前顶点数
int Graph::NumberOfVertices()
{ 
	return numVertices;
};

//返回当前边数
int Graph::NumberOfEdges()
{ 
	return numEdges;
};

// 取顶点 i 的值
 ver Graph::getValue(int i)
{ 
	return VerticesList[i];
};

// 取边上权值
int Graph::getWeight(int v1, int v2)
{
	return Edges[v1][v2];
};

// 给出顶点代码code在图中位置
int Graph::getVertexPos (char code)
{
	for(int i=0;i<numVertices;i++)
		if(VerticesList[i].code==code)
			return i;
	return -1;
};

// 插入一个顶点vertex
bool Graph::insertVertex(char code,string name,string intro)
{  
	if(numVertices==maxVertices)
		return false;
	VerticesList[numVertices].code=code;
	VerticesList[numVertices].name=name;
	VerticesList[numVertices].intro=intro;
	numVertices++;
	return true;
};

// 插入边(v1, v2), 权为cost
bool Graph::insertEdge(int v1, int v2, int weight)
{  
	if(v1>-1 && v1<numVertices && v2>-1 && v2<numVertices)
	{
		Edges[v1][v2]=Edges[v2][v1]=weight;
		numEdges++;
		return true;
	}
	else
		return false;
};

// 输出顶点i的信息
void Graph::Seek(int i)
{
	cout << "景点代号:" << VerticesList[i].code << endl;
	cout << "景点名称:" << VerticesList[i].name << endl;
	cout << "景点简介:" << VerticesList[i].intro << endl;
	cout << "***************************************" << endl;
};

//查询两景点之间的最短路径和距离
void Graph::ShortestPath(int v)
{
	int n=NumberOfVertices();                                 
	dist=new int[n];
	path=new int[n];
	bool * S=new bool[n];                                    //最短路径顶点集 
	int i,j,k,w,min;
	for(i=0;i<n;i++)
	{
		dist[i]=getWeight(v,i);                              //数组初始化 
		S[i]=false;
		if(i!=v&&dist[i]<maxValue)
			path[i]=v;
		else
			path[i]=-1;
	}
	S[v]=true;                                               //顶点v加入顶点集合 
	dist[v]=0;
	for(i=0;i<n-1;i++)
	{
		min=maxValue;
		int u=v;                                             //选不在S中具有最短路径的顶点u 
		for(j=0;j<n;j++)
			if(S[j]==false&&dist[j]<min)
			{
				u=j;
				min=dist[j];
			}
		S[u]=true;                                           //顶点u加入集合S 
		for(k=0;k<n;k++)                                     //修改 
		{         
			w=getWeight(u,k);
			if(S[k]==false&&w<maxValue&&dist[u]+w<dist[k])   //顶点k未加入S,且绕过u可以缩短路径 
			{
				dist[k]=dist[u]+w;
				path[k]=u;                                   //修改到k的最短路径 
			}
		}
	}
};

//输出两景点之间的最短路径和距离
void Graph::CoutShortest(int v,int x)
{
	int j,k,n;
	n=NumberOfVertices();
	int *d=new int[n];
		{
			j=x;
			k=0;
			while(j!=v)
			{
				d[k++]=j;
				j=path[j];
			}
			cout<<getValue(v).name<<"到"<<getValue(x).name<<"的最短路径为:"<<endl<<getValue(v).name;
			while(k>0)
			{
				cout<<"-->"<<getValue(d[--k]).name;
			}
				cout<<endl<<"最短路径长度为:"<<dist[x]<<endl;
			
		}
		delete[] d;
};

//查找两点间的所有路径
void Graph::FindAllPath(int **Array,Node startNodeKey,Node endNodeKey)  
    {  
        result[nPos]=startNodeKey.key;                         //将当前元素放入结果集中  
        Mark[startNodeKey.key-1]=true;                         //将访问标记为已访问 
        nPos++;                                                //结果集索引加1  
        while(nPos!=0)    
        {    
            int tempVal=result[nPos-1];                        //获取到最前面的元素   
            if (tempVal==endNodeKey.key)                       //若当前元素为目标节点  
            {    
                for (int j=0;j<nPos;j++)    
                {    
                    resultPath[pathNum][j]=result[j];          //将结果集复制于最后的路径矩阵中  
                }    
                nPos--;                                        //回溯至上一个节点  
                result[nPos]=0;                                //结果集对应索引置为空  
                pathNum++;                                     //路径数目加1  
                Mark[endNodeKey.key-1]=false;  
                break;    
            }    
            while(startNodeKey.flag<num)                       //利用flag来指示每次的元素的索引    
            {    
                if (Array[tempVal-1][startNodeKey.flag]>0&&Array[tempVal-1][startNodeKey.flag]<maxValue)
                {    
                    if (Mark[startNodeKey.flag]==false)        //利用Mark来判断是否已经访问过该节点    
                    {    
                        Node tempNode;    
                        tempNode.key=startNodeKey.flag+1;    
                        FindAllPath(Array,tempNode,endNodeKey);//深度优先遍历算法,    
                    }               
                }    
                startNodeKey.flag++;                           //索引值相应的加一    
            }    
            if (startNodeKey.flag==num)                        //如果已经是到最后的邻居,说明访问结束,    
            {                                                  //将对应的值置为空    
                nPos--;                                        //再次向上回溯  
                startNodeKey.flag=0;                           //将节点的索引置为空  
                result[nPos]=0;                                //将结果集中对应的索引置为空  
                Mark[startNodeKey.key-1]=false;                //访问之后标记为未访问。因为下面的元素已经访问结束,便于下次的访问  //
                break;    
            }    
        }    
    };
    
//输出两点间的所有路径
void Graph::CoutAllPath(int v1,int v2)
{
	 int x,sum=0;
     Node headNode;//起始节点  
     Node endNode; //终止节点  
     stack<Node> tempStack; 
	for (int i=0;i<num;i++)  
         {  
             for (int j=0;j<num;j++)  
             {  
                 resultPath[i][j]=0;  
             }  
             result[i]=0;  
             Mark[i]=false;  
         }  
         result[num]=0;  
         pathNum=0;  
         nPos=0; 
	    headNode.key=v1+1;
        headNode.flag=0;     //起始节点      
        endNode.key=v2+1;    //结束节点  
        FindAllPath(Edg(),headNode,endNode);  
		cout<<"从"<<getValue(v1).name<<"到"<<getValue(v2).name<<"路径数目为:"<<pathNum<<endl;  
        for (int i=0;i<pathNum;i++)  
        {  
			sum=0;
            cout<<"第"<<i+1<<"条: "; 
			cout<<getValue(headNode.key-1).name;
			v1=headNode.key-1;
            for(int j=1;j<num;j++)  
            {  
                if (resultPath[i][j]==0)  
                {  
                    break;  
                }  
				    x=resultPath[i][j]-1;
					sum+=getWeight (v1,x);
					v1=x;
					cout<<"-->"<<getValue(x).name;		
            } 
			cout <<endl<<"路径长度为:"<<sum<<endl;
        }  
        int i=0;
};

//查找多个顶点间的最佳路径 
int Graph::FindManyPath(int v,int x)
{
	int j,k,n;
	n=NumberOfVertices();
	int *d=new int[n];
		{
			j=x;
			k=0;
			while(j!=v)
			{
				d[k++]=j;
				j=path[j];
			}
			while(k>0)
			{
				cout<<"-->"<<getValue(d[--k]).name;
			}
		}
		delete[] d;
		return dist[x];                     //返回v到x的最短路径 
};

//输出多个顶点间的最佳路径
void Graph::CoutMany() 
{
	system("cls");
	Map();
	int i,j,sum,x,a[num];
	char c[num];
	for(i=0;;i++)
	{
		cout <<"请输入你要参观的第"<<i+1<<"个景点(输入#结束): ";
		cin >>c[i];
		if(c[i]=='#')
			break;
		while(1)
		{
			a[i]=getVertexPos(c[i]);
			if(a[i]==-1)
			{
				cout <<"输入错误,请重新输入"<<endl;
				cout <<"请输入你要参观的第"<<i+1<<"个景点(输入#结束): ";
				cin >>c[i];
			}
			else
			{
				break;
			}
		}	
	}
	cout <<getValue(a[0]).name;
	for(j=0,sum=0;j<i-1;j++)
	{
		ShortestPath(a[j]);
		x=FindManyPath(a[j],a[j+1]);
		sum+=x;
	}
	cout<<endl<<"最短路径长度为:"<<sum<<endl;
	cout <<"按回车键继续";
	getchar();
	getchar();
};

//增加景点和道路 
void Graph::Increase()
{
	int f;
	system("cls");
	Map();
	char code;
	string name;
	string intro;
	cout <<"请输入要增加的景点的代码:";
	cin >>code;
	while(1)
	{
		f=0;
		for(int i=0;i<numVertices;i++)
		{
			if(code==getValue(i).code)
			{
				cout <<"已有该代码请重新输入"<<endl; 
				f=1;
				break;
			}
		}
		if(f==1)
		{
			cout <<"请输入要增加的景点的代码:";
			cin >>code;
		}
		else
		{
			break;
		}
	}
	cout <<"请输入要增加的景点的名称:";
	cin.ignore();
	getline(cin,name);
	cout <<"请输入要增加的景点的简介:";
	getline(cin,intro);
	insertVertex(code,name,intro);
	int v1,v2,weight;
	char code1,code2;
	cout <<"起始景点:";
	cin >>code1;
	cout <<"终止景点:";
	cin>>code2;
	while(1)
	{
	  v1=getVertexPos(code1);
	  v2=getVertexPos(code2);
	  if(v1==-1||v2==-1)
	  {
	    cout <<"输入错误,请重新输入"<<endl;
	    cout << "编号如上图,请输入您要查询的两个景点的编号:"<<endl;
		cout <<"起始景点:";
	    cin >>code1;
	    cout <<"终止景点:";
	    cin>>code2;
	  }
	  else
	   {
		cout <<"请输入两景点间的距离:";
	    cin>>weight;
		insertEdge(v1,v2,weight);
		break;
	   }
	}
	cout <<"按回车键继续";
	getchar();
	getchar();
};

//景点信息查询 
void Graph::search()
{
	int i;
	char code;
	while(1)
	{
		system("cls");
		Map();
		cout <<"请输入要查询的景点编号(输入#退出):";
		cin >> code;
		if(code=='#')
			break;
		i=getVertexPos(code);
		if(i==-1)
		{
			cout <<"输入错误,请重新输入"<<endl;
		}
		else
		{
			Seek(i); 
			cout <<"按回车键继续";
			getchar();
			getchar();
		}
	}
};

//查询两景点间最短距离
void Graph::shorest()
{
	system("cls");
	Map();
	int v1,v2;
	char code1,code2;
	cout << "编号如上图,请输入您要查询的两个景点的编号:"<<endl;
	cout <<"起始景点:";
	cin >>code1;
	cout <<"终止景点:";
	cin>>code2;
	while(1)
	{
	  v1=getVertexPos(code1);
	  v2=getVertexPos(code2);
	  if(v1==-1||v2==-1)
	  {
	    cout <<"输入错误,请重新输入"<<endl;
		cout <<"起始景点:";
	    cin >>code1;
	    cout <<"终止景点:";
	    cin>>code2;
	  }
	  else
	   {
		ShortestPath(v1);
		CoutShortest(v1,v2);
		break;
	   }
	}
	cout <<"按回车键继续";
	getchar();
	getchar();
};

//查询任意两景点间的所有路径
void Graph::allpath()
{
	system("cls");
	Map();
	int v1,v2;
	char code1,code2;
	cout << "编号如上图,请输入您要查询的两个景点的编号:"<<endl;
	cout <<"起始景点:";
	cin >>code1;
	cout <<"终止景点:";
	cin >>code2;
	while(1)
	{
		v1=getVertexPos(code1);
		v2=getVertexPos(code2);
	    if(v1==-1||v2==-1)
		{
		 cout <<"输入错误,请重新输入"<<endl;
		 cout <<"起始景点:";
	     cin >>code1;
	     cout <<"终止景点:";
	     cin>>code2;
		}
		else
		{
		  CoutAllPath(v1,v2);break;
		}
	}
	cout <<"按回车键继续";
	getchar();
	getchar();
};

//动态生成景点列表 
void Graph::Map()
{
	cout << "***************************************" << endl;
	cout << "***景点编号如下:                   ***" << endl;
	for(int i=1;i<=numVertices;i++)
	{
		cout <<VerticesList[i-1].code<<std::left<<setw(15)<<VerticesList[i-1].name;
		if(i%3==0)
		cout <<endl;
	}
	cout <<endl<< "***************************************" << endl;
};

//起始页 
void start()
{
    int i;
    for(i=0; i<10; i++)
    cout<<endl; 
    cout<<"         *********************************************"<<endl;
    cout<<"         **                                         **"<<endl;
    cout<<"         **      欢迎参观济南大学导游图             **"<<endl;
    cout<<"         **                                         **"<<endl;
    cout<<"         *********************************************"<<endl;
    cout<<"按回车键继续......";
    getchar();
}

//菜单页 
void meau()
{
	cout << "*****************************************************************************************************************" << endl;
	cout << "***                                       欢迎使用校园导游咨询系统                                            ***" << endl;
	cout << "***                                       输入1执行景点信息查询                                               ***" << endl;
	cout << "***                                       输入2执行查询两景点间最短距离                                       ***" << endl;
	cout << "***                                       输入3执行查询任意两景点间的所有路径                                 ***" << endl;
	cout << "***                                       输入4执行查询多个景点间的最佳路径                                   ***" << endl;
	cout << "***                                       输入5执行增加景点和道路                                             ***" << endl;
	cout << "***                                       输入0执行退出系统                                                   ***" << endl;
	cout << "*****************************************************************************************************************" << endl;
}

//	########################  程序主入口  ########################
int main()
{
	Graph g;
	string c;
	int choice;
	start();
	system("cls");
	meau();
	while (1)
	{
		system("cls");
		meau();
		cout << "请输入您要执行功能的编号:" ;
		cin >> c;
		if(c.length()==1)
			choice=(c.at(0)-48);
		else
			choice=100;
		if(choice<0||choice>5)
		{
			cout <<"输入错误,请重新输入!"<<endl;
		}
		switch (choice)
		{
		case 1:                                     //景点信息查询 
			g.search();
			break;
		case 2:                                     //查询两景点间最短距离
			g.shorest();
			break;
		case 3:                                     //查询任意两景点间的所有路径
			g.allpath();
			break;
		case 4:                                     //查询多个景点间的最佳路径
			g.CoutMany();
			break;
		case 5:                                     //增加景点和道路 
			g.Increase();
			break;
		case 0:                                     //结束程序 
			cout<<"谢谢您的使用!"<<endl;
			return 0;
		}
	}	
	return 0;									    // 返回退出
}

四、程序运行情况

1、主页面

2、功能页面

3、查询景点信息

输入:a   查询代号为a的景点的信息。

 4、查询两景点的最短路径及最短路径长度

输入:a、e 查询代号为a的景点到代号为e的景点间的所有路径及相应路径长度。

5、查询景点的最佳路径及路径长度

输入:a、b、d 查询代号为a,b,d的景点的最佳路径及路径长度。

 

 6、添加景点

输入:景点代码:t ,景点名称:排球场,景点描述:同学们打排球和上体育的地方。起始景点:a,终止景点:t,景点间距离:800。

五、评价

        在该设计中要求自己设置图,并找出两点间的最短路径及计算最短路径长度,在所有路径的找出和经过景点的最佳路径。用Dijkstra算法来实现初始节点到所有节点的最短路径,根据所需在数组中选择要求的最短路径。所有路径就通过深度搜索算法来实现,借助栈来完成。最佳路径再次运用Dijkstra算法来实现。

功能能够完美的实现,界面也很简洁美观。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值