目录
一、项目介绍
本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务
该系统能够为省级赛事管理解决以下问题:
(1)能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括增加、删除、修改参赛队伍的信息。
(2)从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
(3)能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)
(4)为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)
(5)赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。
二、问题描述
2.1、问题1:
管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项;包括增加、删除、修改参赛队伍的信息。
2.2、问题分析
2.2.1需求分析:
存储输入参赛队伍的基本信息,其中包括对结点数据的查找,并进行增加,删除,并对信息进行修改。
2.2.2要求:
规定每个参赛队必须有一个唯一的编号,以避免重复命名;规定参赛作品的名称必须是唯一的,以避免同名的作品混淆,设置两个结构体,学校的结构体与比赛项目的结构体;
2.2.3容器的选择:
采用vector容器,可以实现动态数组而产生的容器,vector也是一种顺序容器,在内存中连续排列,因此可以通过下标快速访问,时间复杂度为O(1)。连续排列也意味着大小固定,数据超过vector的预定值时vector将自动扩容。
2.2.3涉及的知识:
利用std::getline() 函数从标准输入流 std::cin 中动态获取用户输入,并将其存储到相应的变量中,然后用这些变量初始化一个新的 Team 结构体,并将其添加到向量 teams 中,vector容器中内置函数的用法。
2.3概要设计
2.3.1结构体的定义
struct Team {
int id;//参赛编号
string name;//参赛作品名称
string school;//参赛学校
string category;//赛事类别
vector<string> members;//参赛成员
string coach;//指导老师
//构造函数
Team(int id, string name, string school, string category,
vector<string> members, string coach) :
id(id), name(name), school(school), category(category),
members(members), coach(coach) {};
}
2.3.2定义不同的函数
实现对各参赛基本信息的管理及增添,修改,删除等操作
//增添参赛队伍信息
void add_team(vector<Team>& teams, int& team_id);
//删除参赛队伍信息
void remove_team(vector<Team>& teams) ;
//修改参赛队伍信息信息
void modify_team(vector<Team>& teams)
2.4结果展示
2.4.1输入参赛队伍基本信息并存储
2.4.2选择进行的操作——删除,添加及修改
3.1、问题2:
从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
3.2、问题分析
3.2.1需求分析:
从team.txt中读取基本信息,并实现基于二叉树排序树的查找,若查找成功则输出对应的基本信息,同时计算平均查找长度ASL;否则查找失败
3.2.3涉及的知识:
iostream
包含输入输出流,fstream
包含文件读写相关函数,string
包含字符串相关操作函数,iomanip
用来设置输出格式。
3.3概要设计
3.3.1创建二叉排序树,插入结点及查找操作
// 二叉排序树节点类
struct BinaryTreeNode {
Team data;
BinaryTreeNode* lchild, * rchild;
BinaryTreeNode(Team x):data(x), lchild(NULL), rchild(NULL) {}
};
// 插入节点到二叉排序树
BinaryTreeNode* insert(BinaryTreeNode* root, Team data)
// 查找二叉排序树节点
BinaryTreeNode* search(BinaryTreeNode* root, string team_id)
3.3.2计算ASL
// 计算节点的ASL
void get_asl(int depth, int& node_num, int& path_length_sum, BinaryTreeNode* root) {
if (root == NULL) return;
node_num++;
path_length_sum += depth;
get_asl(depth + 1, node_num, path_length_sum, root->lchild);
get_asl(depth + 1, node_num, path_length_sum, root->rchild);
}
3.3.3从文档team.txt读取文本信息
// 去除字符串中的空格和换行符
void Remove(string& s) {
int index = 0;
if (!s.empty()) {
while ((index = s.find('\t', index)) != string::npos) {
s.erase(index, 1);
}
index = 0;
while ((index = s.find('\n', index)) != string::npos) {
s.erase(index, 1);
}
index = 0;
while ((index = s.find('\r', index)) != string::npos) {
s.erase(index, 1);
}
}
}
// 从文件读取参赛队伍信息
void Read() {
int x = 0;
ifstream i;
i.open("team.txt");
string Temp;
while (getline(i, Temp)) {
Remove(Temp);
for (int j = 0; j < 6; j++) {
int Position = Temp.find('#');
string s = Temp.substr(0, Position);
Temp = Temp.substr(Position + 1);
if (j == 0) {
node[x].id = s;
}
else if (j == 1) {
node[x].name = s;
}
else if (j == 2) {
node[x].school = s;
}
else if (j == 3) {
node[x].category = s;
}
else if (j == 4) {
node[x].members = s;
}
else if (j == 5) {
node[x].coach = s;
}
}
x++;
}
i.close();
}
3..4.4根据队伍编号查找信息
// 根据队伍编号在数组node[]中查找对应的队伍信息
// 若查找成功,返回该队伍在数组中的下标;查找失败,返回-1。
int Search(string id) {
for (int i = 0; i < 10000; i++) {
if (node[i].id == id) {
return i;
}
}
return -1;
}
// 查找队伍信息并输出和计算ASL
void Find() {
string id;
cout << "请输入要查找的队伍编号:" << endl;
cin >> id;
int index = Search(id);
if (index == -1) {
cout << "查找失败!未找到对应队伍。" << endl << endl;
return;
}
// 查找成功,输出队伍基本信息,并计算并输出该队伍的ASL
cout << "队伍基本信息:" << endl;
cout << "参赛队伍编号: " << node[index].id << endl;
cout << "参赛作品名称: " << node[index].name << endl;
cout << "所属学校: " << node[index].school << endl;
cout << "赛事类别: " << node[index].category << endl;
cout << "参赛者信息: " << node[index].members << endl;
cout << "指导老师信息: " << node[index].coach << endl;
Output(index);
cout << "ASL: " << ASL(index) << endl << endl;
}
3.4结果展示
3.4.1从team.txt读取文档并输出
3.4.2在文件中添加队伍基本信息
3.4.5通过编号查找队伍信息并输出
4.1、问题4:
4.1.1需求分析
读取文件并提取参赛编号及赛事类别,根据赛事类别将参赛队伍分到9个参赛室中,并将参赛队伍存放在参赛室中,打印叫号的结果,叫号完毕后,输出进场情况
4.1.2概要设计
// 初始化决赛室
vector<FinalRoom> finalRooms = InitializeFinalRooms();
// 从文件读取参赛队伍信息
vector<Team> teams = ReadTeamsFromFile();
// 叫号并进场
CallAndEnter(finalRooms, teams);
// 打印决赛室的参赛队进场情况
PrintFinalRooms(finalRooms);
// 决赛室叫号功能
while (true) {
int roomNumber;
string teamId;
cout << "请输入决赛室号码和选手编号(输入0退出):";
cin >> roomNumber;
// 输入为0时退出循环
if (roomNumber == 0) {
break;
}
cin >> teamId;
// 决赛室叫号
CallTeamInFinalRoom(finalRooms, roomNumber, teamId);
}
4.1.3结果展示
5.1.1需求分析
设计一个江科大校园导游系统,为来访的客人提供各种信息查询服务,如查询景点信息,找到最短路径
任务定义
设置景点,路径相关信息,构成无向图;提供景点相关信息查询;提供问路查询,找到最短路径。
5.1.2概要设计
设置一个结构体包含景点名称和介绍,再设置一个MGraph,类包含实现功能的函数
Seek(int i)函数查询景点名称以及介绍,使用Floyd()算出最短路径并且输出,Allpaths()输出所有的路径信息,Printshortpath()输出两个景点的最短路径,void meau()展示功能菜单栏选择想要执行的功能
5.1.3算法介绍
弗洛伊德算法,也称为 Floyd-Warshall 算法,是一种动态规划算法,用于解决所有点对之间的最短路径问题。该算法基于递推和分治的思想,可以在 O(n^{3})O(n3) 的时间复杂度内计算出所有点对之间的最短路径。
- 初始化一个二维数组
dist
,用于存储任意两个顶点之间的最短路径长度; - 对于每对顶点 (i,j)(i,j),如果存在一条边连接顶点 ii 和 jj,则将
dist[i][j]
初始化为这条边的权值;否则,将dist[i][j]
初始化为一个较大的数(比如 INF); - 对于每个中间节点 kk,依次更新所有顶点对之间的距离,更新方式为:如果顶点对 (i,j)(i,j) 不经过中间节点 kk 的话,则它们之间的距离
dist[i][j]
不需要更新;否则,它们之间的距离应该为经过中间节点 kk 后的距离dist[i][k] + dist[k][j]
,如果dist[i][j]
大于该值,则更新dist[i][j]
为该值。 - 完成上述更新后,返回
dist
数组即可。
5.1.4参考代码
//使用弗洛伊德算法求解最短路径
void MGraph::Floyd()
{
for (int i = 0; i<vertexNum; i++) //初始化dist和path
for (int j = 0; j<vertexNum; j++)
{
dist[i][j] = arc[i][j];
if (dist[i][j] != 10000)
path[i][j] = a[i].code + a[j].code;
else path[i][j] = " ";
}
for (int k = 0; k<vertexNum; k++) //判定顶点i j之间是否经过k
for (int i = 0; i<vertexNum; i++)
for (int j = 0; j<vertexNum; j++)
if (dist[i][k] + dist[k][j]<dist[i][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = path[i][k] + "-" + path[k][j];
}
}
void MGraph::Allpathlengths()
{
cout << "图的所有路径长如下:" << endl;
for (int i = 0; i < vertexNum; i++) //输出图的各边长信息
{
for (int j = 0; j < vertexNum; j++)
if (dist[i][j] == 10000)
cout << " ";
else
cout << setw(2) << setiosflags(ios::left) << dist[i][j] << " ";//3个字符位置,且左对齐
cout << endl;
}
}