一、课程任务解析
本次课程要求利用数据结构课程所学的相关知识,为中国大学生计算机设计大赛江苏省组委会设计一个省级赛事管理系统。以2021年省赛数据为例,通过对数据的处理和分析,设计合理的数据结构对赛事相关的数据进行存储及处理。赛事相关数据存储在文本文件和excel文件中,文件中不同的数据项之间均使用#分隔,图1中给出了文件team.txt中参赛信息的对应数据示例。
要求该系统能够管理各参赛队的各种信息并能实现对参赛队伍的增加、修改和浏览,同时为各参赛队伍额外分配一个60~100之间的初赛成绩并基于二叉排序树的查找实现参赛队伍的成绩查询
根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者、指导老师信息、初赛成绩),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
此外还为省赛现场设计一个决赛模拟秩序系统。首先进行决赛分组,生成决赛秩序册。所有参赛队按赛事组织文件中的赛事类别分到17个决赛室,输出的参赛团队按初赛成绩降序输出(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择)。
同时赛事系统还要为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。即为查询任意两个目的地(建筑物)之间的一条最短路径。以此来方便参赛选手来参观校园。
二、框架搭建
该项目是基于C++框架而成,通过使用二叉排序树来实现根据提示输入参赛队编号来查找参赛队伍的功能,使用快速排序来实现根据提示输入参赛学校名称来查找参赛队伍的功能。该系统功能选项多样,可以满足赛事管理的基本需求。
三、任务代码
1、任务一:赛事信息管理
(1)、头文件(主要为队伍信息和主要需要调用的函数的声明)
头文件:
#ifndef SUIBIAN_H
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <algorithm>
#include <string>
#include <windows.h>
#include<fstream>
using namespace std;
struct tream
{
string number; //参赛队编号
string name; //参赛作品名称
string school; //参赛学校
string calasses; //赛事类别
string student; //参赛者
string teacher; //指导老师
int sore; //初赛成绩
};
struct node
{
string data;
int num; //存储编号
node* lchid, * rchid;
};
class infomanagement
{
public:
infomanagement();
void read(); //读取数据
void sort(); //生成初赛成绩
void insrett(); //增加参赛队伍
void write(int n); //写如文件(最后一行)
void revamp(string n,int x); //修改参赛初赛
void revam(string y,int y1, string x); //修改参赛信息
void print(); //浏览参赛信息
void printshi(int asd,int n); //输出决赛室信息
void serach(string k); //查询参赛信息
void bittree(); //构建二叉排序树
void group(int x,int y,int n); //将参赛队伍分到17个决赛室
void paixu(int x,int length); //插入排序
void paixuu();
void chishi(); //查看秩序册
void moni(int qwe); //比赛模拟
void InOrder() { InOrder(root); }
void changdi();
private:
tream st[410];
int aa[16][29];
int bb[40];
int tt[18];
int count;
node* insret(node* bt, string x, int xx);
node* search(node* bt, string k);
void InOrder(node* bt);
node* root;
};
#endif
(2)、读取文本并对队伍信息进行修改、查询等
infomanagement::infomanagement()
{
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 29; j++) {
aa[i][j] = 0;
}
}
for (int i = 0; i < 40; i++) {
bb[i] = 0;
}
for (int i = 1; i < 18; i++) {
tt[i] = 0;
}
}
void infomanagement::read()
{
ifstream f;
f.open("team.txt", ios::in);
int i = 0;
count = 1;
string a, b;
if (f.is_open()) {
while (getline(f, a)) {
a.erase(std::remove_if(a.begin(), a.end(),
[](unsigned char c) { return std::isspace(c); }),
a.end());
size_t tt = a.find('#');
st[i].number = a.substr(0, tt);
a = a.substr(tt + 1);
tt = a.find('#');
st[i].name = a.substr(0, tt);
a = a.substr(tt + 1);
tt = a.find('#');
st[i].school = a.substr(0, tt);
a = a.substr(tt + 1);
tt = a.find('#');
st[i].calasses = a.substr(0, tt);
a = a.substr(tt + 1);
tt = a.find('#');
st[i].student = a.substr(0, tt);
a = a.substr(tt + 1);
tt = a.find('#');
st[i].teacher = a.substr(0, tt);
i++;
count++;
}
f.close();
}
else {
cout << "文件打开失败" << endl;
}
} //读取文件
void infomanagement::sort()
{
st[0].sore = 00;
for (int i = 1; i < count; i++) {
st[i].sore = (rand() % (101 - 60)) + 60;
}
} //设置一个60~100的成绩
void infomanagement::insrett()
{
int x = count - 1;
cout << "请依次输入新的信息:" << endl;
cout << "参赛队编号:";
cin >> st[x].number;
cout << "参赛作品名称:";
cin >> st[x].name;
cout << "参赛学校:";
cin >> st[x].school;
cout << "参赛者:";
cin >> st[x].calasses;
cout << "学生姓名:";
cin >> st[x].student;
cout << "指导教师:";
cin >> st[x].teacher;
cout << "初赛成绩:";
cin >> st[x].sore;
cout << "已修改项目:" << endl;
int i = count - 1;
cout << st[i].number << "\t" << st[i].name <<
"\t" << st[i].school << "\t" << st[i].calasses
<< "\t" << st[i].student << "\t" << st[i].teacher
<< "\t" << st[i].sore << endl;
count++;
} //增加一个队伍
void infomanagement::revamp(string n,int x)
{
node* aa;
int i;
aa = search(root, n);
if (aa == nullptr)
cout << "参赛编号错误" << endl;
else {
i = aa->num;
st[i].sore = x;
cout << "修改后的信息为:" << endl;
cout << st[i].number << "\t" << st[i].name <<
"\t" << st[i].school << "\t" << st[i].calasses
<< "\t" << st[i].student << "\t" << st[i].teacher
<< "\t" << st[i].sore << endl;
}
} //修改一个队伍信息
void infomanagement::print()
{
for (int i = 0; i < count-1; i++) {
cout << st[i].number << "\t" << st[i].name <<
"\t" << st[i].school << "\t" << st[i].calasses
<< "\t" << st[i].student << "\t" << st[i].teacher
<< "\t" << st[i].sore << endl;
}
} //打印所有队伍的信息
2、任务二:决赛现场模拟
(1)、将队伍分组并排序
(2)、模拟决赛秩序并动态显示
3、任务三:地图导航系统
(1)、头文件
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
using namespace std;
#define INF INT_MAX //代表没有直达的路径
struct Building { // 建筑物结构体
string name; //建筑物名字
int id; //建筑物编号
};
struct Edge { // 边结构体
int destination; // 目的地建筑物的索引
int distance; // 路径长度
};
class Magraph
{
public:
Magraph();
void vertex(const Building& building); // 添加建筑物
void addPath(const string& source, const string& destination, int distance); // 添加路径
void navigate(const string& src, const string& dest); // 导航函数
private:
vector<Building> buildings; //动态数组buildings[]大小没有指定, 可以动态的向里面添加删除
unordered_map<string, int> buildinghash; // 索引(创建一个key为string类型,value为int类型的unordered_map)
vector<vector<Edge>> adjacencyList; //临界矩阵
void print(const std::vector<std::vector<int>>& next, int source, int destination);
// 递归打印Floyd算法计算的最短路径
};
(2)定义顶点和边的函数
void Magraph::vertex(const Building& building)
{
int index = buildings.size();
buildings.push_back(building); //插入建筑物的数组中
buildinghash[building.name] = index; //根据建筑物的名称确定索引号
adjacencyList.emplace_back();
}
void Magraph::addPath(const string& source, const string& destination, int distance)
{
int sourceIndex = buildinghash[source];
int destinationIndex = buildinghash[destination];
adjacencyList[sourceIndex].push_back({ destinationIndex, distance });
adjacencyList[destinationIndex].push_back({ sourceIndex, distance });//完善邻接矩阵
}
(3)、对导航图做定义
Magraph::Magraph()
{
Building building[10];
building[0] = { "行政中心",0 };
building[1] = { "图书馆",1 };
building[2] = { "东苑食堂",2 };
building[3] = { "南门",3 };
building[4] = { "体育馆",4 };
building[5] = { "西操场",5 };
building[6] = { "经世楼",6 };
building[7] = { "文理大楼",7 };
building[8] = { "西苑食堂",8 };
building[9] = { "三号组团",9 };
for (int i = 0; i < 10; i++) {
vertex(building[i]);
}
addPath("行政中心", "文理大楼", 1000);
addPath("图书馆", "文理大楼", 350);
addPath("图书馆", "西操场", 600);
addPath("图书馆", "东苑食堂", 100);
addPath("东苑食堂", "图书馆", 100);
addPath("东苑食堂", "体育馆", 550);
addPath("南门", "体育馆", 300);
addPath("南门", "三号组团", 750);
addPath("体育馆", "南门", 300);
addPath("体育馆", "东苑食堂", 550);
addPath("体育馆", "西操场", 100);
addPath("体育馆", "西苑食堂", 300);
addPath("西操场", "体育馆", 100);
addPath("西操场", "图书馆", 600);
addPath("西操场", "经世楼", 150);
addPath("西操场", "西苑食堂", 250);
addPath("经世楼", "西操场", 150);
addPath("经世楼", "文理大楼", 150);
addPath("文理大楼", "经世楼", 150);
addPath("文理大楼", "行政楼", 1000);
addPath("西苑食堂", "西操场", 250);
addPath("西苑食堂", "体育馆", 300);
addPath("西苑食堂", "三号组团", 200);
addPath("三号组团", "西苑食堂", 200);
addPath("三号组团", "南门", 750);
}
(4)、根据所选目的地和终点查询最短路径
void Magraph::navigate(const string& src, const string& dest)
{
if (buildinghash.find(src) == buildinghash.end() || buildinghash.find(dest) == buildinghash.end()) {
cout << "输入的起始地或目的地有误,请重新输入。" << endl;
return;
}
int srcIndex = buildinghash[src];
int destIndex = buildinghash[dest];
int numBuildings = buildings.size();
vector<vector<int>> distance(numBuildings, vector<int>(numBuildings, INF)); //全部赋值为最大
vector<vector<int>> next(numBuildings, vector<int>(numBuildings, -1));
// 初始化距离矩阵和下一个节点矩阵
for (int i = 0; i < numBuildings; ++i) {
distance[i][i] = 0;
for (const Edge& edge : adjacencyList[i]) {
distance[i][edge.destination] = edge.distance;
next[i][edge.destination] = edge.destination;
}
}
// Floyd算法计算最短路径和下一个节点
for (int k = 0; k < numBuildings; ++k) {
for (int i = 0; i < numBuildings; ++i) {
for (int j = 0; j < numBuildings; ++j) {
if (distance[i][k] != INF && distance[k][j] != INF &&
distance[i][k] + distance[k][j] < distance[i][j]) {
distance[i][j] = distance[i][k] + distance[k][j];
next[i][j] = next[i][k]; //路径替换从i到j替换为从i到k
}
}
}
}
// 输出最短路径和长度
if (distance[srcIndex][destIndex] != INF) {
cout << "最短路径长度: " << distance[srcIndex][destIndex] << endl;
cout << "路径导航: ";
print(next, srcIndex, destIndex);
cout << endl;
}
else {
cout << "无法找到从 " << src << " 到 " << dest << " 的路径。" << endl;
}
}
void Magraph::print(const std::vector<std::vector<int>>& next, int source, int destination)
{
if (source == destination) {
cout << buildings[source].name;
}
else if (next[source][destination] == -1) {
cout << "无法找到路径。";
}
else {
cout << buildings[source].name << " -> ";
print(next, next[source][destination], destination);
}
}