数据结构课程设计——校园导游咨询

题目要求: 

【问题描述】

    (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.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值