一.问题定义
本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:
2.问题分析
(1)能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括增加、删除、修改参赛队伍的信息。
(2)从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
(3)能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)
(4)为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)
(5)赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。
3.课程设计
(1)参赛队基本信息用结构体(S)表示,包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者和指导老师。
struct Team {
string id;// 参赛队编号
string name; // 参赛作品名称
string school; // 参赛学校
string category; // 赛事类别
string members; // 参赛者
string coach; // 指导老师
};
(2)新增参赛队伍
// 新增参赛队伍
void Event::addTeam(const string& id, const string& name, const string& school, const string& category, const string& member, const string& coach) {
teams.push_back(Team{ id, name, school, category, member, coach }); // 将新的参赛队伍信息添加到队伍列表中
}
(3)删除参赛队伍的信息
//删除参赛队伍的信息
void Event::removeTeam(string id) {
// 使用STL算法查找要删除的参赛队伍
auto it = find_if(teams.begin(), teams.end(), [&](const Team& t) { return t.id == id; });
if (it != teams.end()) {
// 从队列中删除该参赛队伍
teams.erase(it);
}
}
(4)修改参赛队伍的信息
//修改参赛队伍的信息
void Event::updateTeam(const string& id, const string& name, const string& school, const string& category, const string& member, const string& coach) {
// 使用STL算法查找要修改的参赛队伍
auto it = find_if(teams.begin(), teams.end(), [&](const Team& t) { return t.id == id; });
if (it != teams.end()) {
// 修改参赛队伍信息
it->name = name;
it->school = school;
it->category = category;
it->member = member;
it->coach = coach;
}
}
(5)将队列中的队伍信息写入到文件中
void Event::saveToFile(const string& filename) {
ofstream outfile(filename);
if (outfile) {
for (const auto& team : teams) {
outfile << team.id << "#" << team.name << "#" << team.school << "#" << team.category << "#" << team.member << "#" << team.coach << endl;
}
cout << "保存成功!" << endl;
}
else {
cout << "保存文件 " << filename << " 失败!" << endl;
}
}
实现将队列的队伍信息写入到文件中,调用saveToFile()函数将更新后的信息写回文件中,这样就可以直接在team.txt文件中查看到更新后的参赛队伍信息了。
(6)二叉排序树查找参赛队伍的信息
二叉排序树(Binary Search Tree,BST)是一种特殊的二叉树,它具有以下性质:
1. 若左子树非空,则左子树上所有节点的值均小于根节点的值;
2. 若右子树非空,则右子树上所有节点的值均大于根节点的值;
3. 左右子树也分别为二叉排序树;
4. 没有键值相等的节点。
由于二叉排序树具有上述性质,我们可以利用它进行非常高效的查找、插入和删除操作。例如,对于一个有n个节点的二叉排序树,在平均和最坏情况下,查找、插入和删除操作的时间复杂度都为 O(log n)。
void BST::searchHelper(TeamNode* current, string id, int depth) {
if (current == nullptr) {
cout << "查找失败!" << endl;
return;
}
if (id == current->id) {
cout << "基本信息:" << endl;
cout << "作品名称:" << current->name << endl;
cout << "参赛学校:" << current->school << endl;
cout << "赛事类别:" << current->category << endl;
cout << "参赛者:" << current->member << endl;
cout << "指导老师:" << current->coach << endl;
cout << "平均查找长度ASL:" << avgSearchLen() << endl;
return;
}
else if (id < current->id) {
searchHelper(current->left, id, depth + 1);
}
else {
searchHelper(current->right, id, depth + 1);
}
}
插入操作:将新节点插入二叉排序树的过程,需要从根节点出发,比较要插入节点的键值与当前节点的键值的大小关系,依次向左或右子树递归,直到空节点位置。
删除操作:删除指定节点的过程,需要涉及改变英文二叉树的结构,涉及两个场景:要删除的节点没有子节点和要删除的节点有一个子节点,或者要删除的节点有两个子节点。
查找操作:从根节点开始遍历BST,与当前节点的值进行比较大小,递归查找到要查找的节点。
(7)利用Dijkstra设计最短路径
void merge(vector<Team>& Teams, int l, int mid, int r) {
// 合并两个有序数组
vector<Team> tmp(r - l + 1);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r) {
if (Teams[i].id < Teams[j].id) {
tmp[k++] = Teams[i++];
}
else {
tmp[k++] = Teams[j++];
}
}
while (i <= mid) {
tmp[k++] = Teams[i++];
}
while (j <= r) {
tmp[k++] = Teams[j++];
}
for (int p = 0; p < k; p++) {
Teams[l + p] = tmp[p];
}
}
void merge_sort(vector<Team>& Teams, int l, int r) {
// 归并排序的递归实现
if (l >= r) {
return;
}
int mid = l + (r - l) / 2;
merge_sort(Teams, l, mid);
merge_sort(Teams, mid + 1, r);
merge(Teams, l, mid, r);
}
void sort_teams(vector<Team>& Teams) {
// 调用归并排序对 team vector 进行排序
merge_sort(Teams, 0, Teams.size() - 1);
}
这是归并排序的
利用算法可以将江科大地图设计成下面 这个样子,利用Dijkstra算法可以实现查找最短路径。
(8)归并排序
void merge(vector<Team>& Teams, int l, int mid, int r) {
// 合并两个有序数组
vector<Team> tmp(r - l + 1);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r) {
if (Teams[i].id < Teams[j].id) {
tmp[k++] = Teams[i++];
}
else {
tmp[k++] = Teams[j++];
}
}
while (i <= mid) {
tmp[k++] = Teams[i++];
}
while (j <= r) {
tmp[k++] = Teams[j++];
}
for (int p = 0; p < k; p++) {
Teams[l + p] = tmp[p];
}
}
void merge_sort(vector<Team>& Teams, int l, int r) {
// 归并排序的递归实现
if (l >= r) {
return;
}
int mid = l + (r - l) / 2;
merge_sort(Teams, l, mid);
merge_sort(Teams, mid + 1, r);
merge(Teams, l, mid, r);
}
void sort_teams(vector<Team>& Teams) {
// 调用归并排序对 team vector 进行排序
merge_sort(Teams, 0, Teams.size() - 1);
}
这是归并排序的