- 课程设计内容
- 问题概述
- 设计要求
- 概要设计
1、课程设计内容
中国大学生计算机设计大赛是我国高校面向本科生的计算机应用设计大赛,大赛旨在激发学生学习计算机知识和技能的兴趣与潜能,提高学生运用信息技术解决实际问题的综合能力。通过大赛这种计算机教学实践形式,可展示师生的教与学成果,最终以赛促学,以赛促教,以赛促创。该赛事在历届学生中影响力较大,参与者众多,请结合2021届省赛参赛的数据,借助数据结构课程所学的相关知识,通过对数据的处理和分析,熟悉数据结构设计及数据处理在信息管理系统中应用的重要性。
2、问题概述
本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:
(1)能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括增加、删除、修改参赛队伍的信息。
(2)从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
(3)能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)
(4)为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)
(5)赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。
3、设计要求
(1)赛事数据要求存入文件(txt或excel)并能读入查询;
(2)赛地目的地查询,需提供目的地(建筑物)名称、代号、简介、两地之间路径长度等信息;
(3)输入数据形式和范围:赛事相关数据可从键盘输入,或自文件导入。
(4)界面要求:交互设计要合理,每个功能可以设计菜单,用户根据提示,完成相关功能的要
求。
4、概要设计
一 查找系统
struct Team {
string id; // 参赛队编号
string name; // 参赛作品名称
string school; // 参赛学校
string type; // 赛事类别
string member; // 参赛者信息
string tutor; // 指导老师信息
};
struct TreeNode {
Team data;
TreeNode* left; // 左子树指针
TreeNode* right; // 右子树指针
};
TreeNode* root; // 定义全局变量作为根节点指针
int count1 = 0; // 定义全局变量记录添加的队伍数
void Remove(string& s)
{ //去除字符串中的空格
int index = 0;
if (!s.empty()) {
while ((index = s.find('\t', 0)) != string::npos)
{ // 进行转行 ,不然无法清除
s.erase(index, 1);
}
}
}
void Insert(TreeNode*& root, Team team) {
if (root == nullptr) {
root = new TreeNode;
root->data = team;
root->left = nullptr;
root->right = nullptr;
}
else if (team.id < root->data.id) {
Insert(root->left, team);
}
else {
Insert(root->right, team);
}
}
void Read() {
ifstream i;
i.open("team.txt");
string Temp;
while (getline(i, Temp)) {
Remove(Temp);
Team team{};
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)
{
team.id = s;
}
if (j == 1)
{
team.name = s;
}
if (j == 2)
{
team.school = s;
}
if (j == 3)
{
team.type = s;
}
if (j == 4)
{
team.member = s;
}
if (j == 5)
{
team.tutor = s;
}
}
Insert(root, team); // 在读取队伍信息后立即插入到二叉排序树中
count1++; // 每次添加队伍信息后,记录数量加 1
}
cout << "成功读取 " << count1 << " 条队伍信息!\n";
i.close();
}
void InorderTraversal(TreeNode* root) {
if (root != nullptr) {
InorderTraversal(root->left);
cout << "\n参赛队编号:" << root->data.id << "\n"
<< "参赛作品名称:" << root->data.name << "\n"
<< "参赛学校:" << root->data.school << "\n"
<< "参赛类别:" << root->data.type << "\n"
<< "参赛学生姓名:" << root->data.member << "\n"
<< "指导老师姓名:" << root->data.tutor << endl;
cout << endl;
InorderTraversal(root->right);
}
}
void Search() {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
cout << "请输入要查找的参赛队编号:\n";
string id;
cin >> id;
TreeNode* node = root;
while (node != nullptr && node->data.id != id) {
if (id < node->data.id) {
node = node->left;
}
else {
node = node->right;
}
}
if (node != nullptr) {
cout << "\n参赛队编号:" << node->data.id << "\n"
<< "参赛作品名称:" << node->data.name << "\n"
<< "参赛学校:" << node->data.school << "\n"
<< "参赛类别:" << node->data.type << "\n"
<< "参赛学生姓名:" << node->data.member << "\n"
<< "指导老师姓名:" << node->data.tutor << endl;
}
else {
cout << "未找到对应编号的队伍信息!\n";
}
}
该部分为查找系统,包含了基于二叉排序树的队伍信息查找以及读取文件信息并进行输出的功能,目前仅可通过队伍编号进行查找。
二 增删系统
void Insert() {
cout << "请输入参赛队编号:\n";
string id;
cin >> id;
TreeNode* node = root;
while (node != nullptr && node->data.id != id) {
if (id < node->data.id) {
node = node->left;
}
else {
node = node->right;
}
}
if (node != nullptr) {
cout << "该队伍编号已存在,添加失败!\n";
return;
}
Team team{};
team.id = id;
cout << "请输入参赛作品名称:\n";
cin >> team.name;
cout << "请输入参赛学校:\n";
cin >> team.school;
cout << "请输入参赛类别:\n";
cin >> team.type;
cout << "请输入参赛学生姓名:\n";
cin >> team.member;
cout << "请输入指导老师姓名:\n";
cin >> team.tutor;
Insert(root, team);
count1++; // 每次添加队伍信息后,记录数量加 1
cout << "成功添加队伍信息!\n";
}
void Delete() {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
cout << "请输入要删除的参赛队编号:\n";
string id;
cin >> id;
TreeNode* node = root;
while (node != nullptr && node->data.id != id) {
if (id < node->data.id) {
node = node->left;
}
else {
node = node->right;
}
}
if (node == nullptr) {
cout << "未找到对应编号的队伍信息!\n";
return;
}
if (node->left == nullptr) { // 如果只有右子树或没有子节点,则直接将右子树或空指针赋给当前节点的父节点指针
root = node->right;
}
else if (node->right == nullptr) { // 如果只有左子树,则直接将左子树赋给当前节点的父节点指针
root = node->left;
}
else { // 如果被删除节点有两个子节点
TreeNode* parent = nullptr;
TreeNode* minNode = node->right; // 查找右子树中的最小节点
while (minNode->left != nullptr) {
parent = minNode;
minNode = minNode->left;
}
if (parent != nullptr) {
parent->left = minNode->right; // 将右子树中的最小节点的右子树赋给其父节点的左指针
minNode->right = node->right; // 将被删除节点的右子树赋给最小节点的右指针
}
else {
root = minNode; // 如果被删除节点的右子树没有左子树,则直接将右子树赋给当前节点的父节点指针
minNode->left = node->left; // 将被删除节点的左子树赋给最小节点的左指针
}
delete node; // 释放被删除节点的内存空间
count1--; // 每次删除队伍信息后,记录数量减 1
cout << "成功删除队伍信息!\n";
}
}
void Update() {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
cout << "请输入要修改的参赛队编号:\n";
string id;
cin >> id;
TreeNode* node = root;
while (node != nullptr && node->data.id != id) {
if (id < node->data.id) {
node = node->left;
}
else {
node = node->right;
}
}
if (node == nullptr) {
cout << "未找到对应编号的队伍信息!\n";
return;
}
cout << "\n参赛队编号:" << node->data.id << "\n"
<< "参赛作品名称:" << node->data.name << "\n"
<< "参赛学校:" << node->data.school << "\n"
<< "参赛类别:" << node->data.type << "\n"
<< "参赛学生姓名:" << node->data.member << "\n"
<< "指导老师姓名:" << node->data.tutor << endl;
cout << "请选择要修改的信息:\n1.参赛作品名称\n2.参赛学校\n3.参赛类别\n4.参赛学生姓名\n5.指导老师姓名\n";
int choice;
cin >> choice;
switch (choice)
{
case 1:
cout << "请输入新的参赛作品名称:\n";
cin >> node->data.name;
break;
case 2:
cout << "请输入新的参赛学校:\n";
cin >> node->data.school;
break;
case 3:
cout << "请输入新的参赛类别:\n";
cin >> node->data.type;
break;
case 4:
cout << "请输入新的参赛学生姓名:\n";
cin >> node->data.member;
break;
case 5:
cout << "请输入新的指导老师姓名:\n";
cin >> node->data.tutor;
break;
default:
cout << "输入错误!\n";
break;
}
cout << "\n参赛队编号:" << node->data.id << "\n"
<< "参赛作品名称:" << node->data.name << "\n"
<< "参赛学校:" << node->data.school << "\n"
<< "参赛类别:" << node->data.type << "\n"
<< "参赛学生姓名:" << node->data.member << "\n"
<< "指导老师姓名:" << node->data.tutor << endl;
cout << "成功修改队伍信息!\n";
}
该部分为增删系统。包含了添加队伍信息、删除队伍信息、修改队伍信息的功能。
三 叫号系统
void call(int treeSize) {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
// 定义一个map,用来存储赛事类别和对应的参赛队伍
map<string, vector<TreeNode*>> teamMap;
vector<TreeNode*> nodeStack; // 定义一个栈来存储遍历过的节点
nodeStack.push_back(root);
while (!nodeStack.empty()) {
TreeNode* node = nodeStack.back();
nodeStack.pop_back();
if (node != nullptr) {
teamMap[node->data.type].push_back(node); // 根据赛事类别将参赛队伍添加到对应的vector中
nodeStack.push_back(node->right);
nodeStack.push_back(node->left);
}
}
srand((unsigned int)time(NULL)); // 初始化随机数种子
int count = 0;
while (count < treeSize) {
for (int i = 1; i <= 9; i++) { // 循环九次,表示九个决赛室
cout << "=======================\n";
cout << "第 " << i << " 个决赛室叫号:\n";
// 随机选择一支队伍
bool found = false;
for (map<string, vector<TreeNode*>>::iterator it = teamMap.begin(); it != teamMap.end(); ++it) {
vector<TreeNode*> teamVec = it->second;
if (!teamVec.empty()) { // 如果当前类别的队伍还有剩余,则从中选择一个
int teamIndex = rand() % teamVec.size(); // 随机选择一个队伍
TreeNode* teamNode = teamVec[teamIndex];
cout << "参赛队编号:" << teamNode->data.id << "\n"
<< "参赛作品名称:" << teamNode->data.name << "\n"
<< "参赛学校:" << teamNode->data.school << "\n"
<< "参赛类别:" << teamNode->data.type << "\n"
<< "参赛学生姓名:" << teamNode->data.member << "\n"
<< "指导老师姓名:" << teamNode->data.tutor << endl;
// 删除被选择的参赛队伍,避免重复叫号
teamVec.erase(teamVec.begin() + teamIndex);
teamMap[it->first] = teamVec;
count++;
found = true;
break;
}
}
if (!found) { // 如果所有类别的队伍都已经叫完,则直接退出循环
cout << "所有队伍已经叫完!\n";
return;
}
}
}
}
该部分为叫号系统。包含了随机将所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号。可以自行输入需要进行叫号的队伍数量。
四 导航系统
unordered_map<int, vector<pair<int, int>>> graph = {
{1, {{2, 150}, {4, 250}}},
{2, {{1, 150}, {3, 100}, {4, 200}}},
{3, {{2, 100}, {4, 130},{6,120}}},
{4, {{1, 250}, {2, 200}, {3, 150},{5,100},{9,300}}},
{5, {{4, 100}, {6, 150} ,{7,100}}},
{6, {{3, 120}, {5, 150},{8,90}}},
{7, {{5, 100}, {9, 80},{10,100}}},
{8, {{6, 90}, {10, 200}}},
{9, {{4, 300}, {7, 80},{10,40}}},
{10, {{7, 100}, {8, 200}, {9, 40}}}
};
void navigate(int start, int end) {
int n = graph.size();
unordered_map<int, int> dist; // 距离数组存储起点到每个节点的最短距离
priority_queue<pair<int, int>> pq; // 小根堆存储未遍历的节点
pq.push(make_pair(0, start)); // 将起点加入小根堆
for (int i = 1; i <= n; ++i) {
dist[i] = INT_MAX;
}
dist[start] = 0; // 初始化起点距离为0
while (!pq.empty()) {
int node = pq.top().second;
pq.pop();
for (auto neighbor : graph[node]) {
int nextNode = neighbor.first;
int weight = neighbor.second;
int newDistance = dist[node] + weight; // 计算新距离
if (dist.find(nextNode) == dist.end() || dist[nextNode] > newDistance) {
dist[nextNode] = newDistance;
pq.push(make_pair(-newDistance, nextNode));
}
}
}
// 输出最短路径
if (dist.find(end) == dist.end()) {
cout << "无法到达终点!\n";
}
else {
vector<int> path; // 存储路径上的节点
int node = end;
while (node != start) {
path.push_back(node);
for (auto neighbor : graph[node]) {
int prevNode = neighbor.first;
int weight = neighbor.second;
if (dist[node] == dist[prevNode] + weight) {
node = prevNode;
break;
}
}
}
path.push_back(start);
reverse(path.begin(), path.end());
cout << "最短路径为:" << dist[end] <<"米" << ",路径为:" << path[0];
for (int i = 1; i < path.size(); ++i) {
cout << " -> " << path[i];
}
cout << endl;
}
}
该部分为导航系统。可为参赛者提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。
五 主函数
int main() {
int choice;
do {
cout << "\n==========================\n";
cout << "欢迎使用参赛队伍信息管理系统\n";
cout << "--------------------------\n";
cout << "1.读取参赛队伍信息\n";
cout << "2.查找参赛队伍信息\n";
cout << "3.添加参赛队伍信息\n";
cout << "4.删除参赛队伍信息\n";
cout << "5.修改参赛队伍信息\n";
cout << "6.输出所有参赛队伍信息\n";
cout << "7.保存参赛队伍信息到文件\n";
cout << "8.叫号\n";
cout << "9.进场\n";
cout << "10.退出\n";
cout << "==========================\n";
cin >> choice;
switch (choice)
{
case 1:
Read();
break;
case 2:
Search();
break;
case 3:
Insert();
break;
case 4:
Delete();
break;
case 5:
Update();
break;
case 6:
InorderTraversal(root);
break;
case 7:
Write();
break;
case 8:
int num;
cout << "请输入参赛队伍的数量:" << endl;
cin >> num;
call(num);
break;
case 9:
int start, end;
cout << "以下是所有的比赛场地:" << endl;
cout << "--------------------------\n";
cout << "1.3号组团" << endl;
cout << "2.西苑食堂" << endl;
cout << "3.明德园" << endl;
cout << "4.文体中心" << endl;
cout << "5.文心园" << endl;
cout << "6.文理大楼" << endl;
cout << "7.求索园" << endl;
cout << "8.梦溪园" << endl;
cout << "9.东苑食堂" << endl;
cout << "10.图书馆" << endl;
cout << "--------------------------\n";
cout << "请输入起点和终点:\n";
cin >> start >> end;
navigate(start, end);
break;
case 10:
cout << "感谢使用本系统,再见!\n";
exit(0); // 退出程序
break;
default:
cout << "输入错误!\n";
break;
}
} while (choice != 8);
return 0;
}
该代码为主函数。
源代码
#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <vector>
#include <stdlib.h>
#include <stack>
#include <unordered_map>
#include <queue>
#include <climits>
#include <algorithm>
#include <iomanip>
using namespace std;
struct Team {
string id; // 参赛队编号
string name; // 参赛作品名称
string school; // 参赛学校
string type; // 赛事类别
string member; // 参赛者信息
string tutor; // 指导老师信息
};
struct TreeNode {
Team data;
TreeNode* left; // 左子树指针
TreeNode* right; // 右子树指针
};
TreeNode* root; // 定义全局变量作为根节点指针
int count1 = 0; // 定义全局变量记录添加的队伍数
void Remove(string& s)
{ //去除字符串中的空格
int index = 0;
if (!s.empty()) {
while ((index = s.find('\t', 0)) != string::npos)
{ // 进行转行 ,不然无法清除
s.erase(index, 1);
}
}
}
void Insert(TreeNode*& root, Team team) {
if (root == nullptr) {
root = new TreeNode;
root->data = team;
root->left = nullptr;
root->right = nullptr;
}
else if (team.id < root->data.id) {
Insert(root->left, team);
}
else {
Insert(root->right, team);
}
}
void Read() {
ifstream i;
i.open("team.txt");
string Temp;
while (getline(i, Temp)) {
Remove(Temp);
Team team{};
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)
{
team.id = s;
}
if (j == 1)
{
team.name = s;
}
if (j == 2)
{
team.school = s;
}
if (j == 3)
{
team.type = s;
}
if (j == 4)
{
team.member = s;
}
if (j == 5)
{
team.tutor = s;
}
}
Insert(root, team); // 在读取队伍信息后立即插入到二叉排序树中
count1++; // 每次添加队伍信息后,记录数量加 1
}
cout << "成功读取 " << count1 << " 条队伍信息!\n";
i.close();
}
void InorderTraversal(TreeNode* root) {
if (root != nullptr) {
InorderTraversal(root->left);
cout << "\n参赛队编号:" << root->data.id << "\n"
<< "参赛作品名称:" << root->data.name << "\n"
<< "参赛学校:" << root->data.school << "\n"
<< "参赛类别:" << root->data.type << "\n"
<< "参赛学生姓名:" << root->data.member << "\n"
<< "指导老师姓名:" << root->data.tutor << endl;
cout << endl;
InorderTraversal(root->right);
}
}
float asl(TreeNode* root, int depth =0)
{
if (root == nullptr)
{
return 0;
}
else {
float leftASL = asl(root->left, depth + 1);
float rightASL = asl(root->right, depth + 1);
return(leftASL + rightASL + depth);
}
}
void Search() {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
int choice;
cout << "请输入查询方式:\n"
<< "1. 参赛队编号\n"
<< "2. 参赛作品名称\n"
<< "3. 参赛学校\n";
cin >> choice;
bool flag = false; // 用来判断是否找到了匹配的队伍
string keyword;
switch (choice) {
case 1:
cout << "请输入参赛队编号:";
cin >> keyword;
break;
case 2:
cout << "请输入参赛作品名称:";
cin >> keyword;
break;
case 3:
cout << "请输入参赛学校:";
cin >> keyword;
break;
default:
cout << "输入有误,请重新选择。\n";
return;
}
vector<TreeNode*> result; // 用来存储匹配的队伍
vector<TreeNode*> nodeStack; // 定义一个栈来存储遍历过的节点
nodeStack.push_back(root);
while (!nodeStack.empty()) {
TreeNode* node = nodeStack.back();
nodeStack.pop_back();
if (node != nullptr) {
switch (choice) { // 根据选择的方式进行匹配
case 1:
if (node->data.id == keyword) {
result.push_back(node);
flag = true;
}
break;
case 2:
if (node->data.name == keyword) {
result.push_back(node);
flag = true;
}
break;
case 3:
if (node->data.school == keyword) {
result.push_back(node);
flag = true;
}
break;
}
nodeStack.push_back(node->right);
nodeStack.push_back(node->left);
}
}
if (!flag) { // 如果没有找到匹配的队伍,则输出提示信息
cout << "没有找到匹配的队伍!\n";
}
else { // 否则输出所有匹配的队伍信息以及平均查找长度 ASL
cout << "共找到 " << result.size() << " 支队伍:\n";
for (int i = 0; i < result.size(); i++) {
TreeNode* node = result[i];
cout << "参赛队编号:" << node->data.id << "\n"
<< "参赛作品名称:" << node->data.name << "\n"
<< "参赛学校:" << node->data.school << "\n"
<< "参赛类别:" << node->data.type << "\n"
<< "参赛学生姓名:" << node->data.member << "\n"
<< "指导老师姓名:" << node->data.tutor << "\n\n";
}
double asl_num = asl(root) / 398.0;
cout << "平均查找长度 ASL = " << asl_num << endl; // 输出平均查找长度
}
}
void Insert() {
cout << "请输入参赛队编号:\n";
string id;
cin >> id;
TreeNode* node = root;
while (node != nullptr && node->data.id != id) {
if (id < node->data.id) {
node = node->left;
}
else {
node = node->right;
}
}
if (node != nullptr) {
cout << "该队伍编号已存在,添加失败!\n";
return;
}
Team team{};
team.id = id;
cout << "请输入参赛作品名称:\n";
cin >> team.name;
cout << "请输入参赛学校:\n";
cin >> team.school;
cout << "请输入参赛类别:\n";
cin >> team.type;
cout << "请输入参赛学生姓名:\n";
cin >> team.member;
cout << "请输入指导老师姓名:\n";
cin >> team.tutor;
Insert(root, team);
count1++; // 每次添加队伍信息后,记录数量加 1
cout << "成功添加队伍信息!\n";
}
void Delete() {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
cout << "请输入要删除的参赛队编号:\n";
string id;
cin >> id;
TreeNode* node = root;
while (node != nullptr && node->data.id != id) {
if (id < node->data.id) {
node = node->left;
}
else {
node = node->right;
}
}
if (node == nullptr) {
cout << "未找到对应编号的队伍信息!\n";
return;
}
if (node->left == nullptr) { // 如果只有右子树或没有子节点,则直接将右子树或空指针赋给当前节点的父节点指针
root = node->right;
}
else if (node->right == nullptr) { // 如果只有左子树,则直接将左子树赋给当前节点的父节点指针
root = node->left;
}
else { // 如果被删除节点有两个子节点
TreeNode* parent = nullptr;
TreeNode* minNode = node->right; // 查找右子树中的最小节点
while (minNode->left != nullptr) {
parent = minNode;
minNode = minNode->left;
}
if (parent != nullptr) {
parent->left = minNode->right; // 将右子树中的最小节点的右子树赋给其父节点的左指针
minNode->right = node->right; // 将被删除节点的右子树赋给最小节点的右指针
}
else {
root = minNode; // 如果被删除节点的右子树没有左子树,则直接将右子树赋给当前节点的父节点指针
minNode->left = node->left; // 将被删除节点的左子树赋给最小节点的左指针
}
delete node; // 释放被删除节点的内存空间
count1--; // 每次删除队伍信息后,记录数量减 1
cout << "成功删除队伍信息!\n";
}
}
void Update() {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
cout << "请输入要修改的参赛队编号:\n";
string id;
cin >> id;
TreeNode* node = root;
while (node != nullptr && node->data.id != id) {
if (id < node->data.id) {
node = node->left;
}
else {
node = node->right;
}
}
if (node == nullptr) {
cout << "未找到对应编号的队伍信息!\n";
return;
}
cout << "\n参赛队编号:" << node->data.id << "\n"
<< "参赛作品名称:" << node->data.name << "\n"
<< "参赛学校:" << node->data.school << "\n"
<< "参赛类别:" << node->data.type << "\n"
<< "参赛学生姓名:" << node->data.member << "\n"
<< "指导老师姓名:" << node->data.tutor << endl;
cout << "请选择要修改的信息:\n1.参赛作品名称\n2.参赛学校\n3.参赛类别\n4.参赛学生姓名\n5.指导老师姓名\n";
int choice;
cin >> choice;
switch (choice)
{
case 1:
cout << "请输入新的参赛作品名称:\n";
cin >> node->data.name;
break;
case 2:
cout << "请输入新的参赛学校:\n";
cin >> node->data.school;
break;
case 3:
cout << "请输入新的参赛类别:\n";
cin >> node->data.type;
break;
case 4:
cout << "请输入新的参赛学生姓名:\n";
cin >> node->data.member;
break;
case 5:
cout << "请输入新的指导老师姓名:\n";
cin >> node->data.tutor;
break;
default:
cout << "输入错误!\n";
break;
}
cout << "\n参赛队编号:" << node->data.id << "\n"
<< "参赛作品名称:" << node->data.name << "\n"
<< "参赛学校:" << node->data.school << "\n"
<< "参赛类别:" << node->data.type << "\n"
<< "参赛学生姓名:" << node->data.member << "\n"
<< "指导老师姓名:" << node->data.tutor << endl;
cout << "成功修改队伍信息!\n";
}
void Write() {
ofstream o;
o.open("team.txt");
if (!root) {
cout << "暂无队伍信息!\n";
return;
}
vector<TreeNode*> nodeStack; // 定义一个栈来存储遍历过的节点
nodeStack.push_back(root);
while (!nodeStack.empty()) {
TreeNode* node = nodeStack.back();
nodeStack.pop_back();
if (node != nullptr) {
o << node->data.id << "#" << node->data.name << "#" << node->data.school << "#" << node->data.type << "#" << node->data.member << "#" << node->data.tutor << "\n";
nodeStack.push_back(node->right);
nodeStack.push_back(node->left); //实现先遍历右子树再遍历左子树
}
}
cout << "成功写入 " << count1 << " 条队伍信息!\n";
o.close();
}
void call(int treeSize) {
if (root == nullptr) {
cout << "暂无队伍信息!\n";
return;
}
// 定义一个map,用来存储赛事类别和对应的参赛队伍
map<string, vector<TreeNode*>> teamMap;
vector<TreeNode*> nodeStack; // 定义一个栈来存储遍历过的节点
nodeStack.push_back(root);
while (!nodeStack.empty()) {
TreeNode* node = nodeStack.back();
nodeStack.pop_back();
if (node != nullptr) {
teamMap[node->data.type].push_back(node); // 根据赛事类别将参赛队伍添加到对应的vector中
nodeStack.push_back(node->right);
nodeStack.push_back(node->left);
}
}
srand((unsigned int)time(NULL)); // 初始化随机数种子
int count = 0;
while (count < treeSize) {
for (int i = 1; i <= 9; i++) { // 循环九次,表示九个决赛室
cout << "=======================\n";
cout << "第 " << i << " 个决赛室叫号:\n";
// 随机选择一支队伍
bool found = false;
for (map<string, vector<TreeNode*>>::iterator it = teamMap.begin(); it != teamMap.end(); ++it) {
vector<TreeNode*> teamVec = it->second;
if (!teamVec.empty()) { // 如果当前类别的队伍还有剩余,则从中选择一个
int teamIndex = rand() % teamVec.size(); // 随机选择一个队伍
TreeNode* teamNode = teamVec[teamIndex];
cout << "参赛队编号:" << teamNode->data.id << "\n"
<< "参赛作品名称:" << teamNode->data.name << "\n"
<< "参赛学校:" << teamNode->data.school << "\n"
<< "参赛类别:" << teamNode->data.type << "\n"
<< "参赛学生姓名:" << teamNode->data.member << "\n"
<< "指导老师姓名:" << teamNode->data.tutor << endl;
// 删除被选择的参赛队伍,避免重复叫号
teamVec.erase(teamVec.begin() + teamIndex);
teamMap[it->first] = teamVec;
count++;
found = true;
break;
}
}
if (!found) { // 如果所有类别的队伍都已经叫完,则直接退出循环
cout << "所有队伍已经叫完!\n";
return;
}
}
}
}
unordered_map<int, vector<pair<int, int>>> graph = {
{1, {{2, 150}, {4, 250}}},
{2, {{1, 150}, {3, 100}, {4, 200}}},
{3, {{2, 100}, {4, 130},{6,120}}},
{4, {{1, 250}, {2, 200}, {3, 150},{5,100},{9,300}}},
{5, {{4, 100}, {6, 150} ,{7,100}}},
{6, {{3, 120}, {5, 150},{8,90}}},
{7, {{5, 100}, {9, 80},{10,100}}},
{8, {{6, 90}, {10, 200}}},
{9, {{4, 300}, {7, 80},{10,40}}},
{10, {{7, 100}, {8, 200}, {9, 40}}}
};
void navigate(int start, int end) //Dijkstra 算法
{
int n = graph.size();
unordered_map<int, int> dist; // 距离数组存储起点到每个节点的最短距离
priority_queue<pair<int, int>> pq; // 小根堆存储未遍历的节点
pq.push(make_pair(0, start)); // 将起点加入小根堆
for (int i = 1; i <= n; ++i) {
dist[i] = INT_MAX;
}
dist[start] = 0; // 初始化起点距离为0
while (!pq.empty()) {
int node = pq.top().second;
pq.pop();
for (auto neighbor : graph[node]) {
int nextNode = neighbor.first;
int weight = neighbor.second;
int newDistance = dist[node] + weight; // 计算新距离
if (dist.find(nextNode) == dist.end() || dist[nextNode] > newDistance) {
dist[nextNode] = newDistance;
pq.push(make_pair(-newDistance, nextNode));
}
}
}
// 输出最短路径
if (dist.find(end) == dist.end()) {
cout << "无法到达终点!\n";
}
else {
vector<int> path; // 存储路径上的节点
int node = end;
while (node != start) {
path.push_back(node);
for (auto neighbor : graph[node]) {
int prevNode = neighbor.first;
int weight = neighbor.second;
if (dist[node] == dist[prevNode] + weight) {
node = prevNode;
break;
}
}
}
path.push_back(start);
reverse(path.begin(), path.end());
cout << "最短路径为:" << dist[end] <<"米" << ",路径为:" << path[0];
for (int i = 1; i < path.size(); ++i) {
cout << " -> " << path[i];
}
cout << endl;
}
}
int main() {
int choice;
do {
cout << "\n==========================\n";
cout << "欢迎使用参赛队伍信息管理系统\n";
cout << "--------------------------\n";
cout << "1.读取参赛队伍信息\n";
cout << "2.查找参赛队伍信息\n";
cout << "3.添加参赛队伍信息\n";
cout << "4.删除参赛队伍信息\n";
cout << "5.修改参赛队伍信息\n";
cout << "6.输出所有参赛队伍信息\n";
cout << "7.保存参赛队伍信息\n";
cout << "8.对所有参赛队伍进行叫号\n";
cout << "9.导航\n";
cout << "10.退出\n";
cout << "--------------------------\n";
cout << "请选择:";
cin >> choice;
cout << "==========================\n";
switch (choice)
{
case 1:
Read();
break;
case 2:
Search();
break;
case 3:
Insert();
break;
case 4:
Delete();
break;
case 5:
Update();
break;
case 6:
InorderTraversal(root);
break;
case 7:
Write();
break;
case 8:
int num;
cout << "请输入想要叫号的队伍数量:" << endl;
cin >> num;
call(num);
break;
case 9:
int start, end;
cout << "以下是所有的比赛场地:" << endl;
cout << "--------------------------\n";
cout << "1.3号组团" << endl;
cout << "2.西苑食堂" << endl;
cout << "3.明德园" << endl;
cout << "4.文体中心" << endl;
cout << "5.文心园" << endl;
cout << "6.文理大楼" << endl;
cout << "7.求索园" << endl;
cout << "8.梦溪园" << endl;
cout << "9.东苑食堂" << endl;
cout << "10.图书馆" << endl;
cout << "--------------------------\n";
cout << "请输入起点和终点:\n";
cin >> start >> end;
navigate(start, end);
break;
case 10:
cout << "感谢使用本系统,再见!\n";
exit(0); // 退出程序
break;
default:
cout << "输入错误!\n";
break;
}
} while (choice != 10);
return 0;
}