这里附上该设计的源码(.cpp文件)和课程实验报告链接,免费下载!!!
https://download.csdn.net/download/qq_51187087/84121592
一、实验内容
【问题描述】
(1)设计济南大学的校园导游图,所含景点不少于10个。以图中顶点表示学校各景点,存放景点名 称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。
(2)为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。
(3)校园导游图可以根据需要随时增加景点和道路。
(4)可以求出任意两个景点之间的所有路径。
(5)多个景点的最佳访问路线查询,即经过这多个景点的最短路径。
(6)为来访客人提供图中任意景点相关信息的查询。
【测试数据】
根据济南大学校园内的实际情况自己定义一个校园平面图。
【实现提示】
一般情况下,校园的道路是双向通行的,可设校园平面图是无向图。用Dijkstra算法计算最短路径。
目录
二、数据结构设计
校园的道路是双向通行的,可设校园平面图是无向图。定义一个邻接矩阵的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算法来实现。
功能能够完美的实现,界面也很简洁美观。