题目要求:
【问题描述】
(1)设计某大学的校园导游图,所含景点不少于10个。以图中顶点表示学校各景点,存放景点名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。
(2)为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。
(3)校园导游图可以根据需要随时增加景点和道路
(4)可以求出任意两个景点之间的所有路径
(5)多个景点的最佳访问路线查询,即经过这多个景点的最短路径。
(6)为来访客人提供图中任意景点相关信息的查询。
【实现提示】
一般情况下,校园的道路是双向通行的,可设校园平面图是无向图,用Dijkstra算法计算最短路径。
【测试数据】
自己定义并输入一个校园平面图。
测试样例:
以下内容写到data.dat中
10
11
A NULL
B NULL
C NULL
D NULL
E NULL
F NULL
G NULL
H NULL
I NULL
J NULL
A B 2
A E 2
B C 1
B F 1
C E 2
F I 1
I E 1
G E 3
E D 1
D H 1
H E 3
源代码:
Graph.cpp:
/*
功能:图的邻接表实现
输入:读取data.dat文件输入
输出:根据相应函数输出
编译环境:Microsoft Visual Studio Community 2022 (64 位) - Current
修订日期:2022年12月15日
*/
#include "Graph.h"
#include <algorithm>
// 图的成员函数
// 构造函数
Graph::Graph()
{
// Add codes on P341 ... 参见 程序8.7 P341
numVertices = 0;
numEdges = 0;
for ( int i = 0; i < maxVertices; i++ )
NodeTable[i].adj = NULL;
}
// 析构函数 删除邻接表
Graph::~Graph()
{
// Add codes on P342 ... 参见 程序8.7 P342
for ( int i = 0; i < numVertices; i++ )
{
Edge *p = NodeTable[i].adj;
while ( p != NULL )
{
NodeTable[i].adj = p->link;
delete p;
p = NodeTable[i].adj;
}
}
}
// 获取顶点位置
int Graph::getVertexPos( string vertex )
{
// Add codes on P340 ... 参见 程序8.6 P340
for ( int i = 0; i < numVertices; i++ )
if ( NodeTable[i].name == vertex ) return i;
return -1;
};
// 获取顶点的值
string Graph::getValue( int i )
{
// Add codes on P340 ... 参见 程序8.6 P340
if ( i >= 0 && i < numVertices )
return NodeTable[i].name;
};
// 设定顶点的信息
void Graph::setInfo( string v, string info )
{
int index = this->getVertexPos( v );
NodeTable[index].introduction.assign( info );
}
// 获取边的权值
int Graph::getWeight( int v1, int v2 )
{
// Add codes on P342 ... 参见 程序8.8 P342
if ( v1 != -1 && v2 != -1 )
{
Edge *p = NodeTable[v1].adj; // v1的第一条邻接边
while ( p != NULL && p->dest != v2 )
p = p->link;
if ( p != NULL )
return p->cost;
}
return maxWeight; //不存在该边
}
// 插入顶点
bool Graph::insertVertex( const string &vertex, const string &info )
{
// Add codes on P359 ... 参见 程序8.8 P359
if ( numVertices == maxVertices ) return false;
NodeTable[numVertices].name = vertex; // 插入在表的最后
NodeTable[numVertices].introduction = info;
NodeTable[numVertices].no = numVertices;
numVertices++;
return true;
};
// 删除顶点 以及和它相关联的边
bool Graph::removeVertex( string vertex )
{
int v; // 定义内部编号变量
v = getVertexPos( vertex ); // 调用私有函数,将输入数据转换成内部编号
// Add codes on P343 ... 参见 程序8.8 P343
if ( v<0 || v>numVertices ) // v不在图中,不删除
{
cout << "输入顶点有误!" << endl;
return false;
}
if ( numVertices == 1 ) // 仅剩一个顶点,不删除该顶点
return false;
Edge *p, *s, *t; int k; // 定义临时变量、算法结构控制变量
while ( NodeTable[v].adj != NULL ) // 顶点有边,即有邻接点
{
p = NodeTable[v].adj; k = p->dest; // 取邻接顶点
s = NodeTable[k].adj; t = NULL; // 令邻接顶点的邻接顶点(即指向本待删除顶点)为空
while ( s != NULL && s->dest != v )
{
t = s;
s = s->link;
}
if ( s != NULL )
{
if ( t == NULL )
NodeTable[k].adj = s->link;
else
t->link = s->link;
delete s;
}
NodeTable[v].adj = p->link;
delete p; numEdges--;
}
numVertices--;
NodeTable[v].name = NodeTable[numVertices].name; // 填补
p = NodeTable[v].adj = NodeTable[numVertices].adj;
while ( p != NULL )
{
s = NodeTable[p->dest].adj;
while ( s != NULL )
{
if ( s->dest == numVertices )
{
s->dest = v;
break;
}
else
s = s->link;
}
p = p->link; // 课本遗漏,补充
}
return true;
};
// 插入边
bool Graph::insertEdge( string vtx1, string vtx2, int weight )
{
int v1, v2; // 定义内部编号变量
v1 = getVertexPos( vtx1 ); // 输入数据转换成内部编号
v2 = getVertexPos( vtx2 );
// Add codes on P344 ... 参见 程序8.8 P344
if ( ( v1 > -1 && v1 < numVertices ) && ( v2 > -1 && v2 < numVertices ) )
{
Edge *q, *p = NodeTable[v1].adj;
while ( p != NULL && p->dest != v2 )
p = p->link;
if ( p != NULL ) return false;
p = new Edge; q = new Edge;
p->dest = v2; p->cost = weight;
p->link = NodeTable[v1].adj;
NodeTable[v1].adj = p;
q->dest = v1; q->cost = weight;
q->link = NodeTable[v2].adj;
NodeTable[v2].adj = q;
numEdges++; // 边数变量增加
return true;
}
return false;
};
// 删除边
bool Graph::removeEdge( string vtx1, string vtx2 )
{
int v1, v2; // 定义内部编号变量
v1 = getVertexPos( vtx1 ); // 输入数据转换成内部编号
v2 = getVertexPos( vtx2 );
// Add codes on P344 ... 参见 程序8.8 P34
return false;
};
// 判断a点与b点是否邻接
bool Graph::isNeighbor( int a, int b )
{
if ( a == -1 || b == -1 || a == b )
return false;
Edge *p = NodeTable[a].adj;
while ( p != NULL )
{
if ( p->dest == b )
return true;
p = p->link;
}
return false;
}
判断a点与b点是否连通(DFS)
//bool Graph::isConnect( int a, int b )
//{
// int num = this->NumberOfVertices();
// int *visited = new int[num];
// Vector<int> stack;
// for ( int i = 0; i < num; i++ )
// visited[i] = false;
// stack.push_back( a );
// visited[a] = true;
// while ( !stack.empty() )
// {
// int top;
// stack.getTop( top );
// stack.pop_back();
//
// }
// return false;
//}
// 获取顶点 v 的第一个邻接顶点
int Graph::getFirstNeighbor( int v )
{
// Add codes on P342 ... 参见 程序8.8 P342
if ( v != -1 )
{
Edge *p = NodeTable[v].adj;
if ( p != NULL )
return p->dest;
}
return -1;
};
// 获取顶点 v 的下一个邻接顶点 w
int Graph::getNextNeighbor( int v, int w )
{
// Add codes on P342 ... 参见 程序8.8 P342
if ( v != -1 )
{
Edge *p = NodeTable[v].adj;
while ( p != NULL && p->dest != w )
p = p->link;
if ( p != NULL && p->link != NULL )
return p->link->dest;
}
return -1;
};
// 输出图的邻接表
void Graph::printSheet()
{
cout << "邻接表输出:" << endl;
int num = this->NumberOfVertices();
for ( int i = 0; i < num; i++ )
{
Edge *p = this->NodeTable[i].adj;
cout << i << " " << this->getValue( i );
//cout << this->getValue( i );
while ( p != NULL )
{
cout << " --> " << this->getValue( p->dest )
<< " (" << this->getWeight( i, p->dest ) << "m)";
p = p->link;
}
cout << endl;
}
}
// 显示所有信息
void Graph::showAllInfo()
{
int num = this->NumberOfVertices();
for ( int i = 0; i < num; i++ )
{
cout << "地点名称:" << NodeTable[i].name << "\t"
<< "代号:" << NodeTable[i].no << "\n"
<< "简介:\n";
cout << NodeTable[i].introduction << endl << endl;
}
cout << "共计 " << num << " 个地点" << endl << endl;
}
// 两点间的最短路径
bool Graph::shortestPath( string v1, string v2 )
{
int start = this->getVertexPos( v1 ), end = this->getVertexPos( v2 );
if ( start == -1 || end == -1 )
{
cout << "提示:有不存在的地点,请检查后重新输入" << endl;
return false;
}
int n = this->NumberOfVertices();
int i, j, k, w, min; // 相关操作变量
int *path = new int[n];
int len = this->Dijkstra( start, end, path );
cout << v1;
for ( int i = 1; path[i] != -1 && i < n; i++ )
cout << " - " << this->getValue( path[i] );
cout << "\n最短路径长度:" << len << "m" << endl << endl;
return true;
}
// 读取Dijkstra算法所获得的路径
void Graph::pathTransform( int start, int end, int *path )
{
int n = this->NumberOfVertices(), i, j;
int *arr = new int[n];
arr[0] = end;
for ( i = 1; arr[i - 1] != start; i++ )
arr[i] = path[arr[i - 1]];
for ( i -= 1, j = 0; i >= 0; i--, j++ )
path[j] = arr[i];
path[j] = -1;
}
// Dijkstra算法
int Graph::Dijkstra( int start, int end, int *path)
{
int n = this->NumberOfVertices();
bool *S = new bool[n]; // 建立点集
int i, j, k, w, min; // 相关操作变量
int *dist = new int[n];
for ( i = 0; i < n; i++ )
{
dist[i] = this->getWeight( start, i );
S[i] = false;
if ( i != start && dist[i] < maxWeight )
path[i] = start;
else
path[i] = -1;
}
S[start] = true; // 顶点start(v1)加入点集
dist[start] = 0;
for ( i = 0; i < n - 1; i++ )
{
min = maxWeight;
int u = start; // 选择不在S中具有最短路径的点u
for ( j = 0; j < n; j++ )
if ( S[j] == false && dist[j] < min )
{ // 另一个未访问,且两点构成的路径最短
u = j;
min = dist[j];
}
S[u] = true;
for ( k = 0; k < n; k++ ) // 修改dist数组
{
w = this->getWeight( u, k );
if ( S[k] == false && w < maxWeight && dist[u] + w < dist[k] )
{
dist[k] = dist[u] + w;
path[k] = u;
}
}
}
pathTransform( start, end, path );
return dist[end];
}
// 获取并输出某一点的信息
bool Graph::printInfo( string vertex )
{
int index = this->getVertexPos( vertex );
if ( index >= 0 && index < maxVertices )
{
cout << "\n地点名称:" << NodeTable[index].name << "\t"
<< "代号:" << NodeTable[index].no << "\n"
<< "简介:\n";
cout << NodeTable[index].introduction << endl << endl;
return true;
}
else
cout << "提示:未找到该地点,请重新尝试!" << endl;
return false;
}
// 两点间的所有路径 https://www.cnblogs.com/maydow/p/4839376.html
bool Graph::searchAllPath( string v1, string v2 )
{
int start = this->getVertexPos( v1 ), end = this->getVertexPos( v2 );
if ( start == -1 || end == -1 )
return false;
int num = this->NumberOfVertices();
bool *visited = new bool[num];
for ( int i = 0; i < num; i++ )
visited[i] = false;
//vector<int> stack;
Vector<int> vector;
findAllPath( start, end, visited, vector );
return true;
}
// 搜寻两点间的所有路径
void Graph::findAllPath( int v1, int v2, bool *visited, Vector<int> &vector )
{
if ( v1 == -1 || visited[v1] == true ) // 若当前节点已经访问过,返回
return;
vector.push_back( v1 );
visited[v1] = true; // 已访问
if ( v1 == v2 ) // 找到目标点,输出
{
cout << getMessage( vector );
vector.pop_back();
visited[v1] = false;
return;
}
Edge *p = NodeTable[v1].adj;
while ( p != NULL ) // 遍历这个点的所有邻接点
{
findAllPath( p->dest, v2, visited, vector );
p = p->link;
}
visited[v1] = false; // 搜索完毕,清除标志
vector.pop_back();
}
// 遍历栈输出
string Graph::getMessage(Vector<int> &stack )
{
//vector<int>::iterator it = stack.begin();
string message = "";
//for ( ; it < stack.end(); it++ )
// message += this->getValue( *it ) + " -> ";
for ( int i = 0; i < stack.size(); i++ )
message += this->getValue( stack[i] ) + " -> ";
if ( stack.size() == 0 )
return message;
return message.substr( 0, message.length() - 4 ) + '\n';
}
// 多途径点的最短路径
bool Graph::multiPointsSP( string v1, string v2, int num, string *vertices )
{
// Step0 获取顶点序号,以及初始化
int n = this->NumberOfVertices();
int start = this->getVertexPos( v1 ), end = this->getVertexPos( v2 );
if ( start == -1 || end == -1 )
return false;
int *points = new int[num], *path = new int[n];
int dist = maxWeight;
for ( int i = 0; i < n; i++ )
path[i] = -1;
for ( int i = 0; i < num; i++ )
{
points[i] = this->getVertexPos( vertices[i] );
if ( points[i] == -1 )
return false;
}
// Step1 判断中间节点(points)的连通情况
//for ( int i = 0; i < num; i++ )
// for ( int j = i + 1; j < num; j++ )
// //if ( this->getWeight( points[i], points[j] ) == -1 )
// if ( !isConnect( points[i], points[j] ) )
// return false;
// Step2 中间节点(points)形成全排列,计算两个中间节点间的最短路径
int midPath = maxWeight, *spath = new int[n], *mpath = new int[n], *epath = new int[n];
for ( int i = 0; i < n; i++ )
spath[i] = mpath[i] = epath[i] = -1;
do {
midPath = pathMidNode( num, points, mpath );
// 路径长度 = start到points[0]最短路径 + 中间最短路径 + points[num-1]到end最短路径
int temp = Dijkstra( start, points[0], spath ) + midPath +
Dijkstra( points[num - 1], end, epath );
if ( temp < dist )
dist = temp;
} while ( next_permutation( points, points + num ) ); // points从第0个元素到第num个元素的全排列
// Step3 输出路径
cout << v1;
for ( int i = 1; spath[i] != -1 && i < n; i++ )
cout << " - " << getValue( spath[i] );
for ( int i = 1; mpath[i] != -1 && i < n; i++ )
cout << " - " << getValue( mpath[i] );
for ( int i = 1; epath[i] != -1 && i < n; i++ )
cout << " - " << getValue( epath[i] );
cout << "\n路径长度:" << dist << "m" << endl;
return true;
}
// 中间节点的最短路径
int Graph::pathMidNode( int num, int *arr, int *path )
{
int dist = 0, index = 0;
for ( int i = 0; i < num - 1; i++ )
{
if ( this->isNeighbor( arr[i], arr[i + 1] ) )
{
dist += this->getWeight( arr[i], arr[i + 1] );
path[index++] = arr[i];
path[index++] = arr[i + 1];
}
else
{
int *dpath = new int[num], j;
dist += Dijkstra( arr[i], arr[i + 1], dpath );
for ( int k = 0; dpath[k] != -1 || k < num; k++ )
path[index++] = dpath[k];
}
}
return dist;
}
// 友元函数——重载流输入函数
istream &operator>> ( istream &is, Graph &G )
{
//Add codes on P338 ... 参见 程序8.5 P338 Stream-input overloading function
int i, j, k, n, m;
string v1, v2, info;
int weight;
cout << "输入地点个数n和路径条数m: " << endl;
is >> n >> m; // 输入点数和边数
cout << "输入n个地点名称及其简介(简介中不得含有任何空白字符):\n样例:十教\n第十教学楼" << endl;
for ( i = 0; i < n; i++ ) // 输入n个顶点
{
is >> v1 >> info;
G.insertVertex( v1, info );
//G.setInfo( v1, info );
}
cout << "输入m条路径和路径长度,按“点 点 权”输入\n样例: 十教 升华广场 100" << endl;
i = 0;
while ( i < m ) // 输入m条边
{
is >> v1 >> v2 >> weight; // 输入边的“点-点-权”
j = G.getVertexPos( v1 ); // 查顶点号
k = G.getVertexPos( v2 );
if ( i == -1 || k == -1 )
cout << "提示:有不存在的地点,请重试" << endl;
else
{
//G.insertEdge(j,k,weight); // 按照“点-点-权”插入边
G.insertEdge( v1, v2, weight );
i++;
}
}
return is;
};
// 友元函数——重载流输出函数
ostream &operator << ( ostream &os, Graph &G )
{
// Add codes on P338 ... 参见 程序8.5 P338 Stream-output overloading function
cout << endl << "输出图:" << endl;
int i, j, n, m;
string e1, e2;
int w;
n = G.NumberOfVertices();
m = G.NumberOfEdges();
cout << "顶点数与边数分别为:" << endl;
cout << n << ", " << m << endl; // 输出顶点数与边数
cout << "所有" << m << "个边的\"点-点-权\"分别为:" << endl;
for ( i = 0; i < n; i++ )
for ( j = i + 1; j < n; j++ )
{
w = G.getWeight( i, j );
if ( w > 0 )
{
e1 = G.getValue( i );
e2 = G.getValue( j );
os << "(" << e1 << "," << e2 << "," << w << ")" << endl;
}
}
cout << endl;
return os;
};
// 友元函数——从文件中获取Graph点与边
bool CreateGraphFromFile( Graph &G )
{
cout << "正在读取data.dat文件..." << endl;
char filename[128] = { "data.dat" }; // 保存文件名的变量
ifstream dataFile( filename );
if ( !dataFile.is_open() )
{
cout << "文件无法打开,请确认data.dat是否存在" << endl;
return false;
}
char buffer[256];
int numVtx; // 输入点数
dataFile >> numVtx;
dataFile.getline( buffer, 255 );
int numEdges; // 输入边数
dataFile >> numEdges;
dataFile.getline( buffer, 255 );
string v, info; // 顶点类型的临时变量
for ( int i = 0; i < numVtx; i++ ) // 输入所有的顶点
{
dataFile >> v >> info; // 输入顶点名称
G.insertVertex( v, info );
//G.setInfo( v, info );
}
dataFile.getline( buffer, 255 );
cout << "地点数: " << G.NumberOfVertices() << endl;
string vtx1, vtx2; // 边起始端点序号(非名称)的临时变量
int e; // 边类型的临时变量
for ( int i = 0; i < numEdges; i++ ) // 输入所有的边
{
dataFile >> vtx1 >> vtx2 >> e;
G.insertEdge( vtx1, vtx2, e );
dataFile.getline( buffer, 255 );
}
cout << "路径数: " << G.NumberOfEdges() << endl;
dataFile.close();
cout << "文件读取成功!" << endl << endl;
return true; // 返回
};
Graph.h:
/*
功能:Graph.cpp所对应的h文件
输入:无
输出:无
编译环境:Microsoft Visual Studio Community 2022 (64 位) - Current
修订日期:2022年12月15日
*/
#pragma once
#include <iostream>
#include <fstream>
#include <string>
//#include <vector>
#include "Vector.cpp"
using namespace std;
#define maxVertices 100
#define maxWeight 5000
class Graph;
istream &operator>> ( istream &is, Graph &G );
ostream &operator<< ( ostream &os, Graph &G );
bool CreateGraphFromFile( Graph &G );
// 边的结构体定义
struct Edge
{
int dest; // 边上另一顶点的位置
int cost; // 边的权值
Edge *link; // 下一条边
Edge() {}
Edge( int num, int weight ) : dest( num ), cost( weight ), link( NULL ) {}
};
// 点的结构体定义
struct Vertex
{
string name;
int no;
string introduction;
Edge *adj;
};
// 图的类定义
class Graph
{
friend istream &operator>> ( istream &in, Graph &G ); // 友元:重载流输入
friend ostream &operator<< ( ostream &out, Graph &G ); // 友元:重载流输出
friend bool CreateGraphFromFile( Graph &G ); // 友元:文件输入
private:
Vertex NodeTable[maxVertices]; // 点的邻接表
int getVertexPos( string vertex ); // 顶点在表中的序号
protected:
int numEdges; // 当前边数
int numVertices; // 当前顶点数
public:
Graph();
~Graph();
bool GraphEmpty() const // 判图空否
{
return numEdges == 0;
}
int NumberOfVertices() // 返回当前顶点数
{
return numVertices;
}
int NumberOfEdges() // 返回当前边数
{
return numEdges;
}
string getValue( int i ); // 取顶点 i 的值
int getWeight( int v1, int v2 ); // 返回(v1, v2)边上的权值
void setInfo( string v, string info ); // 设定顶点的信息
bool insertVertex( const string &vertex, const string &info ); // 插入一个顶点vertex
bool removeVertex( string vertex ); // 删去顶点 v 和所有与相关联边
bool insertEdge( string vtx1, string vtx2, int weight ); // 插入边(v1, v2), 权为weight
bool removeEdge( string vtx1, string vtx2 ); // 在图中删去边(v1,v2);形参类型符合实际应用
bool isNeighbor( int a, int b ); // 判断a点与b点是否邻接
//bool isConnect( int a, int b ); // 判断a点与b点是否连通
int getFirstNeighbor( int v ); // 取顶点 v 的第一个邻接顶点
int getNextNeighbor( int v, int w ); // 取邻接顶点 w 的下一邻接顶点
void printSheet(); // 输出图的邻接表
void showAllInfo(); // 输出所有顶点的信息
bool shortestPath( string v1, string v2 ); // 两点间的最短路径
int Dijkstra( int start, int end, int *path ); // Dijkstra算法
void pathTransform( int start, int end, int *path );// 读取Dijkstra算法所获得的路径
bool printInfo( string vertex ); // 获取并输出某一点的信息
bool searchAllPath( string v1, string v2 ); // 两点间的所有路径
void findAllPath( int v1, int v2, bool *visited, Vector<int> &vector );// 搜寻两点间的所有路径
string getMessage( Vector<int> &vector ); // 遍历栈输出
bool multiPointsSP( string v1, string v2, int num, string *vertices ); // 多途径点的最短路径
int pathMidNode( int num, int *arr, int *path ); // 中间节点的最短路径
};
Page.cpp:
/*
功能:展示系统页面
输入:无
输出:根据相应函数输出
编译环境:Microsoft Visual Studio Community 2022 (64 位) - Current
修订日期:2022年12月15日
*/
#include <iostream>
#include <cstdio>
#include "Page.h"
using namespace std;
void printCenter( string str )
{
int len = str.length();
int a = ( 70 - len ) / 2;
while ( a-- )
cout << " ";
cout << str << endl;
}
void line()
{
cout << "---------------------------------------------------------------------" << endl;
}
void welcome( Graph &graph )
{
line();
printCenter( "欢迎使用校园导游咨询系统" );
line();
cout << " (1) 显示所有景点\t\t\t(2) 查询景点信息\n"
<< " (3) 增加景点或路径\t\t\t(4) 批量增加景点和路径\n"
<< " (5) 查询两景点间的所有路径\t\t(6) 查询两景点间的最短路径\n"
<< " (7) 查询多个景点的最佳访问路线\t(8) 退出\n";
line();
cout << "请选择..." << endl;
string choice;
int num = 0;
while ( cin >> choice )
{
num = choice[0] - '0';
if ( choice.length() == 1 && num >= 1 && num <= 8 )
break;
else
cout << "输入有误,请检查并重新输入..." << endl;
}
switch ( num )
{
case 1: page1( graph ); break;
case 2: page2( graph ); break;
case 3: page3( graph ); break;
case 4: page4( graph ); break;
case 5: page5( graph ); break;
case 6: page6( graph ); break;
case 7: page7( graph ); break;
case 8: cout << "提示:退出程序" << endl; break;
default: cout << "提示:程序提前终止" << endl; break;
}
}
void page1( Graph &graph )
{
system( "cls" );
line();
printCenter( "主界面/显示所有景点" );
line();
graph.showAllInfo();
system( "pause" );
system( "cls" );
welcome( graph );
}
void page2( Graph &graph )
{
system( "cls" );
line();
printCenter( "主界面/查询景点信息" );
line();
cout << "请输入景点名称(输入exit可退出此页面)..." << endl;
string str;
while ( cin >> str )
{
getchar();
if ( str == "exit" )
break;
if ( graph.printInfo( str ) )
{
cout << "继续查询?y/[n]" << endl;
char ch = getchar();
if ( ch == 'y' || ch == 'Y' )
cout << "请输入景点名称..." << endl;
else if ( ch == '\n' || ch == 'n' || ch == 'N' )
break;
else
break;
}
}
system( "cls" );
welcome( graph );
}
void page3( Graph &graph )
{
system( "cls" );
line();
printCenter( "主界面/增加(1)景点或(2)路径" );
line();
cout << "输入样例:\n1 景点名称 简介\n2 景点一 景点二 120" << endl << endl;
cout << "请选择增加项目和内容(默认一直增加,输入exit可退出此页面)..." << endl;
string choice;
while ( cin >> choice )
{
if ( choice == "exit" )
break;
string str1, str2;
if ( choice == "1" )
{
cin >> str1 >> str2;
if ( !graph.insertVertex( str1, str2 ) )
cout << "提示:有不存在的点,请检查后重新尝试" << endl;
else
cout << "景点添加成功" << endl;
}
else if ( choice == "2" )
{
int n;
cin >> str1 >> str2 >> n;
if(!graph.insertEdge(str1,str2,n) )
cout << "提示:有不存在的点,请检查后重新尝试" << endl;
else
cout << "路径添加成功" << endl;
}
else
cout << "提示:所选项目序号(1或2)有误,请重新尝试" << endl;
}
// 保存到data.dat
system( "cls" );
welcome( graph );
}
void page4( Graph &graph )
{
system( "cls" );
line();
printCenter( "主界面/批量增加景点和路径" );
line();
cout << "请按要求输入..." << endl << endl;
while ( cin >> graph )
{
getchar();
cout << "增加完毕,继续增加?y/[n]" << endl;
char ch = getchar();
if ( ch == 'y' || ch == 'Y' )
cout << "请按要求输入..." << endl;
else if ( ch == '\n' || ch == 'n' || ch == 'N' )
break;
else
break;
}
// 保存到data.dat
system( "cls" );
welcome( graph );
}
void page5( Graph &graph )
{
system( "cls" );
line();
printCenter( "主界面/查询两景点间的所有路径" );
line();
cout << "请输入两景点名称(输入exit可退出此页面)..." << endl;
string str1, str2;
while ( cin >> str1 )
{
if ( str1 == "exit" )
break;
cin >> str2; getchar();
if ( graph.searchAllPath( str1, str2 ) )
{
cout << "继续查询?(y/[n])" << endl;
char ch = getchar();
if ( ch == 'y' || ch == 'Y' )
cout << "请输入两景点名称(输入exit可退出此页面)..." << endl;
else if ( ch == '\n' || ch == 'n' || ch == 'N' )
break;
else
break;
}
}
system( "cls" );
welcome( graph );
}
void page6( Graph &graph )
{
system( "cls" );
line();
printCenter( "主界面/查询两景点间的最短路径" );
line();
cout << "请输入两景点名称(输入exit可退出此页面)..." << endl;
string str1, str2;
while ( cin >> str1 )
{
if ( str1 == "exit" )
break;
cin >> str2; getchar();
if ( graph.shortestPath( str1, str2 ) )
{
cout << "继续查询?(y/[n])" << endl;
char ch = getchar();
if ( ch == 'y' || ch == 'Y' )
cout << "请输入两景点名称(输入exit可退出此页面)..." << endl;
else if ( ch == '\n' || ch == 'n' || ch == 'N' )
break;
else
break;
}
}
system( "cls" );
welcome( graph );
}
void page7( Graph &graph )
{
system( "cls" );
line();
printCenter( "主界面/查询多个景点的最佳访问路线" );
line();
cout << "请按要求输入..." << endl;
string str1, str2, *str;
int num;
cout << "路线起点:";
cin >> str1;
cout << "路线终点:";
cin >> str2;
cout << "途径地点的个数(不得少于1):";
cin >> num;
str = new string[num];
for ( int i = 0; i < num; i++ )
{
cout << "途径点" << i + 1 << ": ";
cin >> str[i];
}
graph.multiPointsSP( str1, str2, num, str );
system( "pause" );
system( "cls" );
welcome( graph );
}
Page.h:
/*
功能:Page.cpp所对应的h文件
输入:无
输出:无
编译环境:Microsoft Visual Studio Community 2022 (64 位) - Current
修订日期:2022年12月15日
*/
#pragma once
#include <iostream>
#include "Graph.h"
using namespace std;
void printCenter( string str );
void line();
void welcome( Graph &graph );
void page1( Graph &graph );
void page2( Graph &graph );
void page3( Graph &graph );
void page4( Graph &graph );
void page5( Graph &graph );
void page6( Graph &graph );
void page7( Graph &graph );
Vector.cpp:
/*
功能:链式栈(参考STL中的Vector进行部分改造)
输入:无
输出:无
编译环境:Microsoft Visual Studio Community 2022 (64 位) - Current
修订日期:2022年12月15日
*/
#include <assert.h>
#include <iostream>
#include <cstdlib>
using namespace std;
const int maxStack = 20;
const int stackIncrement = 20;
template <class T>
class Vector
{
public:
Vector( int sz = 50 );
~Vector() { delete[]elements; }
void push_back( T &x );
bool pop_back();
bool getTop( T &x );
bool empty() const { return ( top == -1 ) ? true : false; }
bool IsFull() const { return ( top == maxSize - 1 ) ? true : false; }
int size() { return top + 1; }
void MakeEmpty() { top = -1; }
T operator[]( int index ) { return elements[index]; }
private:
T *elements;
int top;
int maxSize;
void overflowProcess();
};
template <class T>
Vector<T>::Vector( int sz ) :top( -1 ), maxSize( sz )
{
elements = new T[maxSize];
assert( elements != NULL );
}
template <class T>
void Vector<T>::overflowProcess()
{ //扩容栈
T *newArray = new T[maxSize + stackIncrement];
if ( newArray == NULL )
{
cerr << "存储分配失败!" << endl;
exit( 1 );
}
for ( int i = 0; i <= top; i++ )
newArray[i] = elements[i];
maxSize = maxSize + stackIncrement;
delete[]elements;
elements = newArray;
}
template <class T>
void Vector<T>::push_back( T &x )
{
if ( IsFull() == true )
overflowProcess();
elements[++top] = x;
}
template <class T>
bool Vector<T>::pop_back()
{
if ( empty() == true )
return false;
elements[top--];
return true;
}
template <class T>
bool Vector<T>::getTop( T &x )
{
if ( empty() == true )
return false;
x = elements[top];
return true;
}
Main.cpp:
/*
功能:系统主函数
输入:无
输出:根据相应函数输出
编译环境:Microsoft Visual Studio Community 2022 (64 位) - Current
修订日期:2022年12月15日
*/
#include <iostream>
#include "Graph.h"
#include "Page.h"
using namespace std;
int main()
{
Graph graph;
CreateGraphFromFile( graph );
welcome( graph );
return 0;
}
参考文献:
[1] 殷人昆. 数据结构(用面向对象方法与C++语言描述)(第3版)[M]. 北京: 清华大学出版社, 2019.7.
[2] 黄书力, 胡大裟, 蒋玉明. 经过指定的中间节点集的最短路径算法[J]. 计算机工程与应用, 2015(11):6.