1、问题定义
对参赛队的基本信息进行存储和修改
2、问题分析
需要考虑如何去对参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项;包括增加、删除、修改参赛队伍的信息。这需要使用一个数据结构来进行储存和进行相应的操作。我使用了向量来储存数据。
3、概要设计
数据结构设计
结点信息的数据结构:结构体——team 用于存储队伍的的详细信息,如参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师。
struct Team {
string id; // 参赛队编号
string name; // 参赛作品名称
string school; // 参赛学校
string category; // 赛事类别
string members; // 参赛者
string teacher; // 指导老师
};
这里所有的数据都使用字符串来存储,解释一下为什么不用int来存储。
考虑到后面对文本的读取,第一行的文本如下图
第一行的编号为字符串形式,若直接使用try catch进行抛出处理,会导致后文中的对数据进行删改增加后的数据产生确实所以定义id为string类型。
这是对文本中水平制表符的过滤函数trim,对字符串进行首尾的查询,如果存在水平制表符则删除首尾的水平制表符,并返回一个新的字符串。如果输入字符串中只包含制表符,则将其清空并返回一个空字符串。
std::string trim(std::string s) {
if (!s.empty()) {
auto start = s.find_first_not_of("\t");
auto end = s.find_last_not_of("\t");
if (start == std::string::npos) {
s.clear();
}
else {
s = s.substr(start, end - start + 1);
}
}
return s;
}
readTeamFromFile是向量对文件的读取的函数
值得注意的是由于对id的读取是分两种情况的,所以使用了 bool firstLine = true;来判别读取的是否为第一行,若为第一行直接存储,其他行则先将它转换为int再转换为字符串。team
对象的 id
成员变量的类型是 std::string
,而 field
的类型也是 std::string
。如果直接将 field
赋值给 team
对象的 id
成员变量,编译器会报错,提示类型不匹配。因此,需要将 field
先转换为整型 int
,然后再将其转换为字符串类型,并将其赋值给 team
对象的 id
成员变量。
vector<Team> readTeamsFromFile(string filename) {
vector<Team> teams;
ifstream fin(filename);
if (fin.is_open()) {
string line;
bool firstLine = true;
while (getline(fin, line)) {
Team team;
int pos = 0;
for (int i = 0; i < 6; i++) {
int next = line.find('#', pos);
string field = line.substr(pos, next - pos);
field = trim(field); // 调用 trim 函数修剪字段内容
if (i == 0) {
if (firstLine) {
team.id = field;
firstLine = false;
}
else {
team.id = to_string(stoi(field));
}
}
else if (i == 1) {
team.name = field;
}
else if (i == 2) {
team.school = field;
}
else if (i == 3) {
team.category = field;
}
else if (i == 4) {
team.members = field;
}
else if (i == 5) {
team.teacher = field;
}
pos = next + 1;
}
teams.push_back(team);
}
fin.close();
}
else {
cout << "无法打开文件 " << filename << endl;
}
return teams;
}
1、问题定义
如何建立二叉排序树来根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。请输出ASL(成功)的计算公式和结果值。
2、问题分析
如何建立二叉排序树,输入得到二叉排序树的节点,所有节点的深度和节点个数,二叉排序树的asl=所有节点的深度/节点个数。
通过对二叉排序树的节点进行遍历,得到所有节点的深度和节点个数
3、概要设计
数据结构设计
参赛队的数据结构:定义二叉排序
// 定义二叉排序树节点结构体
struct Node {
string id; // 参赛队编号
Team team; // 参赛队信息
Node* left; // 左子节点指针
Node* right; // 右子节点指针
};
对于二叉排序树的构建
1、就是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2、若它的右子树不空,则右子树上所有节点的值均大于其根节点的值。
3、换句话说就是:任何节点的键值一定大于其左子树中的每一个节点的键值,并小于其右子树中的每一个节点的键值。
// 构建二叉排序树
Node* buildBST(vector<Team>& teams) {
Node* root = nullptr; // 创建根节点指针,初始化为空
for (int i = 1; i < teams.size(); i++) { // 循环遍历向量中的每个元素
Node* node = new Node; // 创建一个新节点
node->id = teams[i].id; // 设置节点的编号
node->team = teams[i]; // 设置节点的参赛队信息
node->left = nullptr; // 初始化左子节点指针为空
node->right = nullptr; // 初始化右子节点指针为空
if (root == nullptr) { // 如果根节点为空,将新节点设置为根节点
root = node;
}
else { // 否则,将新节点插入到二叉排序树中
Node* p = root; // 创建一个指针p,指向根节点
while (true) { // 不断循环,直到找到合适的插入位置
if (node->id < p->id) { // 如果要插入的节点编号小于当前节点编号
if (p->left == nullptr) { // 如果当前节点的左子节点为空,将新节点插入到左子节点
p->left = node;
break;
}
else { // 否则,继续向左子树查找
p = p->left;
}
}
else { // 如果要插入的节点编号大于等于当前节点编号
if (p->right == nullptr) { // 如果当前节点的右子节点为空,将新节点插入到右子节点
p->right = node;
break;
}
else { // 否则,继续向右子树查找
p = p->right;
}
}
}
}
}
return root; // 返回根节点指针
}
但由于上文中对文件的读取,把id为参赛队伍编号也读取进内存,会导致节点数多出一个,对此我在上述二叉树建立的函数中,我将遍历元素i,,从1开始。
二叉树查找函数
bool queryTeam(Node* root, string id) {
if (root == nullptr) { // 如果根节点为空,说明查找失败
cout << "查找失败!" << endl;
return false;
}
if (root->id == id) { // 如果找到了指定编号的参赛队信息
Team team = root->team; // 获取当前参赛队信息
// 输出当前参赛队信息到屏幕上
cout << "参赛作品名称:" << team.name << endl;
cout << "参赛学校:" << team.school << endl;
cout << "赛事类别:" << team.category << endl;
cout << "参赛者:" << team.members << endl;
cout << "指导老师:" << team.teacher << endl;
return true; // 返回成功标志
}
else if (id < root->id) { // 如果要查找的编号小于当前节点编号,向左子树查找
return queryTeam(root->left, id);
}
else { // 如果要查找的编号大于当前节点编号,向右子树查找
return queryTeam(root->right, id);
}
}
首先获取指定编号的参赛队信息,若成功输出相关信息。否则失败,若编号小于当前节点编号,向左字数查找,递归。否则就是大于当前节点编号,向右字数查找,递归。
对二叉树的遍历函数
void traverseBST(Node* root, int depth, int& count, int& depthSum) {
if (root == nullptr) { // 如果根节点为空,直接返回
return;
}
count++; // 节点个数加1
depthSum += depth; // 深度之和加上当前节点的深度
traverseBST(root->left, depth + 1, count, depthSum); // 遍历左子树
traverseBST(root->right, depth + 1, count, depthSum); // 遍历右子树
通过遍历的方法得到不同层的节点数和深度,相加得到节点深度总和,深度总和。
1、问题定义
能够提供按参赛学校查询参赛团队,根据提示输入参赛学校名称,若查找成功,输出该学校参赛的所有团队的基本信息,输出的参赛团队需有序输出(按参赛队编号)。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)
2、问题分析
使用什么排序来输出参赛队编号
因为数据量较大,采用归并排序的方法,来排序。
(19条消息) 排序——归并排序(Merge sort)_努力的老周的博客-CSDN博客
3、概要设计
排序函数如下
void merge(vector<Team>& teams, int left, int mid, int right) {
int i = left, j = mid + 1, k = 0;
vector<Team> temp(right - left + 1);
while (i <= mid && j <= right) {
if (teams[i].id <= teams[j].id) {
temp[k++] = teams[i++];
}
else {
temp[k++] = teams[j++];
}
}
while (i <= mid) {
temp[k++] = teams[i++];
}
while (j <= right) {
temp[k++] = teams[j++];
}
for (i = 0; i < k; i++) {
teams[left + i] = temp[i];
}
}
void mergeSort(vector<Team>& teams, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(teams, left, mid);
mergeSort(teams, mid + 1, right);
merge(teams, left, mid, right);
}
}
增删修改的函数如下
void queryTeam1(vector<Team>& teams) {
string category;
cout << "请输入要查询的赛事类别:" << endl;
cin >> category;
// 归并排序
mergeSort(teams, 0, teams.size() - 1);
// 输出排序后的参赛队信息
for (int i = 0; i < teams.size(); i++) {
if (teams[i].category == category) {
Team team = teams[i];
cout << "编号:" << team.id << endl;
cout << "作品名称:" << team.name << endl;
cout << "学校:" << team.school << endl;
cout << "类别:" << team.category << endl;
cout << "参赛者:" << team.members << endl;
cout << "指导老师:" << team.teacher << endl;
}
}
}
void addTeam(vector<Team>& teams) {
Team team;
cout << "请输入参赛队伍信息:" << endl;
cout << "编号:";
cin >> team.id;
cout << "作品名称:";
cin >> team.name;
cout << "学校:";
cin >> team.school;
cout << "类别:";
cin >> team.category;
cout << "参赛者:";
cin >> team.members;
cout << "指导老师:";
cin >> team.teacher;
teams.push_back(team);
cout << "添加成功!" << endl;
}
// 删除参赛队伍信息
void deleteTeam(vector<Team>& teams) {
int id;
cout << "请输入要删除的参赛队伍编号:";
cin >> id;
for (auto it = teams.begin(); it != teams.end(); it++) {
if (it->id == to_string(id)) {
teams.erase(it);
cout << "删除成功!" << endl;
return;
}
}
cout << "未找到该参赛队伍!" << endl;
}
// 修改参赛队伍信息
void modifyTeam(vector<Team>& teams) {
int id;
cout << "请输入要修改的参赛队伍编号:";
cin >> id;
for (auto& team : teams) {
if (team.id == to_string(id)) {
cout << "请输入新的参赛队伍信息:" << endl;
cout << "作品名称:";
cin >> team.name;
cout << "学校:";
cin >> team.school;
cout << "类别:";
cin >> team.category;
cout << "参赛者:";
cin >> team.members;
cout << "指导老师:";
cin >> team.teacher;
return;
}
}
cout << "未找到该参赛队伍!" << endl;
}
// 将参赛队伍信息写入文件
void writeToFile(const vector<Team>& teams, const string& filename) {
ofstream outfile(filename);
if (outfile.is_open()) {
for (const auto& team : teams) {
outfile << team.id << "\t#\t" << team.name << "\t#\t" << team.school << "\t#\t" << team.category << "\t#\t" << team.members << "\t#\t" << team.teacher << endl;
}
outfile.close();
cout << "参赛队伍信息已写入文件 " << filename << " 中!" << endl;
}
else {
cout << "无法打开文件 " << filename << "!" << endl;
}
}
void mergeSort(vector<Team>& teams, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(teams, left, mid);
mergeSort(teams, mid + 1, right);
merge(teams, left, mid, right);
}
}
1、问题定义
为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,各参赛队进场比赛时间可设为0.5秒)
2、问题分析
将9个赛事类别加入不同的rooms[]中,,最后按序输出。
3、概要设计
数据结构设计
结点信息的数据结构:结构体——Room 用于存储决赛室的编号和参赛队列。
// 定义全局变量
const int NUM_ROOMS = 9; // 决赛室数量
Room rooms[NUM_ROOMS]; // 决赛室数组
定义全局变量方便后面存储
// 定义全局变量
const int NUM_ROOMS = 9; // 决赛室数量
Room rooms[NUM_ROOMS]; // 决赛室数组
将不同类别的赛事存入不同的数组
void add_team(vector<Team>& teams)
{
// 定义需要用到的变量和常量
char strs1[3][20] = { {"大数据实践"} };
char strs2[4][30] = { {"信息图形设计"}, {"动态信息影像(MG动画)"}, {"交互信息设计"}, {"数据可视化"} };
char strs3[4][30] = { {"人工智能实践赛"} };
char strs4[5][30] = { {"Web应用与开发"}, {"管理信息系统 "}, {"算法设计与应用"}, {"移动应用开发"} };
char strs5[5][30] = { {"医药卫生"}, {"数字生活"}, {"运动健身 "}, {"城市管理 "}, {"行业应用"} };
char strs6[5][30] = { {"动画"}, {"纪录片"}, {"数字短片"}, {"微电影 "}, {"新媒体漫画"} };
char strs7[5][30] = { {"产品设计"}, {"环境设计"}, {"平面设计"} };
char strs8[5][30] = { {"交互媒体设计"}, {"游戏设计"}, {"虚拟现实VR与增强现实AR"} };
char strs9[5][50] = { {"汉语言文学"}, {"计算机基础与应用类课程微课"}, {"虚拟实验平台"}, {"中、小学数学或自然科学课程微课"} };
// 将strs存入一个vector中,方便遍历
vector<const char*> strs;
strs.insert(strs.end(), strs1, strs1 + 1);
strs.insert(strs.end(), strs2, strs2 + 4);
strs.insert(strs.end(), strs3, strs3 + 1);
strs.insert(strs.end(), strs4, strs4 + 4);
strs.insert(strs.end(), strs5, strs5 + 5);
strs.insert(strs.end(), strs6, strs6 + 5);
strs.insert(strs.end(), strs7, strs7 + 3);
strs.insert(strs.end(), strs8, strs8 + 3);
strs.insert(strs.end(), strs9, strs9 + 4);
// 定义队列
queue<Team> q1, q2, q3, q4, q5, q6, q7, q8, q9;
mergeSort(teams, 0, teams.size() - 1);
// 遍历teams,将相同category的team加入相应的队列
for (int i = 0; i < teams.size(); ++i) {
const char* category = teams[i].category.c_str();
for (int j = 0; j < strs.size(); ++j) {
if (strcmp(category, strs[j]) == 0) {
if (j==0)
q1.push(teams[i]);
else if(j>0 && j<=4)
q2.push(teams[i]);
else if (j > 4 && j <=5 )
q3.push(teams[i]);
else if (j > 5 && j <= 9)
q4.push(teams[i]);
else if (j > 9 && j <= 14)
q5.push(teams[i]);
else if (j > 14 && j <= 19)
q6.push(teams[i]);
else if (j > 19 && j <= 22)
q7.push(teams[i]);
else if (j > 22 && j <= 25)
q8.push(teams[i]);
else if (j > 25 && j <=29)
q9.push(teams[i]);
}
}
}
// 将队列存入全局变量的rooms数组中
rooms[0] = { 1, q1 };
rooms[1] = { 2, q2 };
rooms[2] = { 3, q3 };
rooms[3] = { 4, q4 };
rooms[4] = { 5, q5 };
rooms[5] = { 6, q6 };
rooms[6] = { 7, q7 };
rooms[7] = { 8, q8 };
rooms[8] = { 9, q9 };
}
将九类的赛事分别定义,如果符合一类赛事中任一一个,将其加入相应的队列。最后将决赛房间号与队列绑定。
对叫号系统的模拟函数
void call_teams() {
// 循环遍历所有决赛室
for (int i = 0; i < NUM_ROOMS; ++i) {
// 当前决赛室
Room& room = rooms[i];
// 当前决赛室队列不为空时,循环叫号
while (!room.teams.empty()) {
// 输出叫号信息
cout << "决赛室" << room.id << "请题目为:" << room.teams.front().name << "参赛队进场比赛" << endl;
// 模拟参赛队进场比赛0.5秒
this_thread::sleep_for(chrono::milliseconds(5));
// 弹出队首元素
room.teams.pop();
}
}
}
1、问题定义
赛事系统为参赛者提供赛地的校园导游程序。为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供图中任意目标地(建筑物)的问路查询,即查询任意两个目的地(建筑物)之间的一条最短的简单路径。
2、问题分析
导航是一个无向图的问题,使用邻接表来存储,使用dijkstra算法
3、概要设计
数据结构设计
结点信息的数据结构:邻接表
adjList[1].push_back(make_pair(2, 100)); // 添加从节点 1 到节点 2 权值为 100 的边
adjList[1].push_back(make_pair(4, 200)); // 添加从节点 1 到节点 4 权值为 200 的边
adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
adjList[2].push_back(make_pair(4, 150)); // 添加从节点 2 到节点 4 权值为 150 的边
adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
adjList[3].push_back(make_pair(2, 80)); // 添加从节点 3 到节点 2 权值为 80 的边
adjList[3].push_back(make_pair(5, 120)); // 添加从节点 3 到节点 5 权值为 120 的边
adjList[3].push_back(make_pair(6, 110)); // 添加从节点 3 到节点 6 权值为 110 的边
adjList[4].push_back(make_pair(1, 200)); // 添加从节点 4 到节点 1 权值为 200 的边
adjList[4].push_back(make_pair(2, 150)); // 添加从节点 4 到节点 2 权值为 150 的边
adjList[4].push_back(make_pair(5, 50)); // 添加从节点 4 到节点 5 权值为 50 的边
adjList[5].push_back(make_pair(3, 120)); // 添加从节点 5 到节点 3 权值为 120 的边
adjList[5].push_back(make_pair(4, 50)); // 添加从节点 5 到节点 4 权值为 50 的边
adjList[5].push_back(make_pair(8, 150)); // 添加从节点 5 到节点 8 权值为 150 的边
adjList[5].push_back(make_pair(9, 230)); // 添加从节点 5 到节点 9 权值为 230 的边
adjList[6].push_back(make_pair(3, 110)); // 添加从节点 6 到节点 3 权值为 110 的边
adjList[6].push_back(make_pair(7, 80)); // 添加从节点 6 到节点 7 权值为 80 的边
adjList[6].push_back(make_pair(8, 80)); // 添加从节点 6 到节点 8 权值为 80 的边
adjList[7].push_back(make_pair(6, 80)); // 添加从节点 7 到节点 6 权值为 80 的边
adjList[7].push_back(make_pair(10, 100)); // 添加从节点 7 到节点 10 权值为 100 的边
adjList[8].push_back(make_pair(5, 150)); // 添加从节点 8 到节点 5 权值为 150 的边
adjList[8].push_back(make_pair(6, 60)); // 添加从节点 8 到节点 6 权值为 60 的边
adjList[8].push_back(make_pair(9, 90)); // 添加从节点 8 到节点 9 权值为 90 的边
adjList[8].push_back(make_pair(10, 70)); // 添加从节点 8 到节点 10 权值为 70 的边
adjList[9].push_back(make_pair(5, 230)); // 添加从节点 9 到节点 5 权值为 230 的边
adjList[9].push_back(make_pair(8, 90)); // 添加从节点 9 到节点 8 权值为 90 的边
adjList[9].push_back(make_pair(10, 50)); // 添加从节点 9 到节点 10 权值为 50 的边
adjList[10].push_back(make_pair(7, 100)); // 添加从节点 10 到节点 7 权值为 100 的边
adjList[10].push_back(make_pair(8, 70)); // 添加从节点 10 到节点 8 权值为 70 的边
adjList[10].push_back(make_pair(9, 50)); // 添加从节点 10 到节点 9 权值为 50 的边
dijkstra算法的实现
// 定义无穷大常量INF,用于表示路径长度的上限
const int INF = numeric_limits<int>::max();
// Dijkstra算法实现
void dijkstra(vector<vector<pair<int, int>>>& adjList, int start, int end, vector<string>& names, vector<string>& descriptions) {
int n = adjList.size();
// 定义距离数组dist和前驱数组prev
vector<int> dist(n, INF);
vector<int> prev(n, -1);
// 将起点的距离设为0
dist[start] = 0;
// 定义优先队列pq,用于存储待处理的节点
// 优先队列中存储节点到起点的距离和节点编号,按距离从小到大排序
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push(make_pair(0, start));
// 循环处理待处理的节点,直到队列为空
while (!pq.empty()) {
// 取出距离起点最近的节点
int u = pq.top().second;
pq.pop();
// 遍历该节点的邻居节点
for (auto v : adjList[u]) {
// 计算该邻居节点到起点的距离
int alt = dist[u] + v.second;
// 如果新的距离比原来的距离更短,则更新距离和前驱节点
if (alt < dist[v.first]) {
dist[v.first] = alt;
prev[v.first] = u;
// 将该邻居节点加入优先队列
pq.push(make_pair(dist[v.first], v.first));
}
}
}
// 如果终点的距离为无穷大,则表示没有可达路径
if (dist[end] == INF) {
cout << "No path found" << endl;
}
else {
// 输出最短路径的长度
cout << "Shortest path length: " << dist[end] << endl;
// 输出最短路径的节点序列
cout << "Path: ";
vector<int> path;
int cur = end;
while (cur != -1) {
path.push_back(cur);
cur = prev[cur];
}
for (int i = path.size() - 1; i >= 0; i--) {
cout << names[path[i]] << " ";
}
cout << endl;
// 输出终点的名称和描述
cout << "Destination: " << names[end] << endl;
cout << "Description: " << descriptions[end] << endl;
}
}
Dijkstra算法详解 通俗易懂 - 知乎 (zhihu.com)
完整的代码
#include<iostream>
#include <fstream>
#include <iostream>
#include<queue>
#include<vector>
#include<string>
#include <algorithm>
#include <thread>
#include <chrono>
#include<unordered_map>
using namespace std;
std::string trim(std::string s) {
if (!s.empty()) {
auto start = s.find_first_not_of("\t");
auto end = s.find_last_not_of("\t");
if (start == std::string::npos) {
s.clear();
}
else {
s = s.substr(start, end - start + 1);
}
}
return s;
}
struct Team {
string id; // 参赛队编号
string name; // 参赛作品名称
string school; // 参赛学校
string category; // 赛事类别
string members; // 参赛者
string teacher; // 指导老师
};
vector<Team> readTeamsFromFile(string filename) {
vector<Team> teams;
ifstream fin(filename);
if (fin.is_open()) {
string line;
bool firstLine = true;
while (getline(fin, line)) {
Team team;
int pos = 0;
for (int i = 0; i < 6; i++) {
int next = line.find('#', pos);
string field = line.substr(pos, next - pos);
field = trim(field); // 调用 trim 函数修剪字段内容
if (i == 0) {
if (firstLine) {
team.id = field;
firstLine = false;
}
else {
team.id = to_string(stoi(field));
}
}
else if (i == 1) {
team.name = field;
}
else if (i == 2) {
team.school = field;
}
else if (i == 3) {
team.category = field;
}
else if (i == 4) {
team.members = field;
}
else if (i == 5) {
team.teacher = field;
}
pos = next + 1;
}
teams.push_back(team);
}
fin.close();
}
else {
cout << "无法打开文件 " << filename << endl;
}
return teams;
}
// 定义二叉排序树节点结构体
struct Node {
string id; // 参赛队编号
Team team; // 参赛队信息
Node* left; // 左子节点指针
Node* right; // 右子节点指针
};
// 二叉排序树查找函数
bool queryTeam(Node* root, string id) {
if (root == nullptr) { // 如果根节点为空,说明查找失败
cout << "查找失败!" << endl;
return false;
}
if (root->id == id) { // 如果找到了指定编号的参赛队信息
Team team = root->team; // 获取当前参赛队信息
// 输出当前参赛队信息到屏幕上
cout << "参赛作品名称:" << team.name << endl;
cout << "参赛学校:" << team.school << endl;
cout << "赛事类别:" << team.category << endl;
cout << "参赛者:" << team.members << endl;
cout << "指导老师:" << team.teacher << endl;
return true; // 返回成功标志
}
else if (id < root->id) { // 如果要查找的编号小于当前节点编号,向左子树查找
return queryTeam(root->left, id);
}
else { // 如果要查找的编号大于当前节点编号,向右子树查找
return queryTeam(root->right, id);
}
}
// 构建二叉排序树
Node* buildBST(vector<Team>& teams) {
Node* root = nullptr; // 创建根节点指针,初始化为空
for (int i = 1; i < teams.size(); i++) { // 循环遍历向量中的每个元素
Node* node = new Node; // 创建一个新节点
node->id = teams[i].id; // 设置节点的编号
node->team = teams[i]; // 设置节点的参赛队信息
node->left = nullptr; // 初始化左子节点指针为空
node->right = nullptr; // 初始化右子节点指针为空
if (root == nullptr) { // 如果根节点为空,将新节点设置为根节点
root = node;
}
else { // 否则,将新节点插入到二叉排序树中
Node* p = root; // 创建一个指针p,指向根节点
while (true) { // 不断循环,直到找到合适的插入位置
if (node->id < p->id) { // 如果要插入的节点编号小于当前节点编号
if (p->left == nullptr) { // 如果当前节点的左子节点为空,将新节点插入到左子节点
p->left = node;
break;
}
else { // 否则,继续向左子树查找
p = p->left;
}
}
else { // 如果要插入的节点编号大于等于当前节点编号
if (p->right == nullptr) { // 如果当前节点的右子节点为空,将新节点插入到右子节点
p->right = node;
break;
}
else { // 否则,继续向右子树查找
p = p->right;
}
}
}
}
}
return root; // 返回根节点指针
}
void traverseBST(Node* root, int depth, int& count, int& depthSum) {
if (root == nullptr) { // 如果根节点为空,直接返回
return;
}
count++; // 节点个数加1
depthSum += depth; // 深度之和加上当前节点的深度
traverseBST(root->left, depth + 1, count, depthSum); // 遍历左子树
traverseBST(root->right, depth + 1, count, depthSum); // 遍历右子树
}
void merge(vector<Team>& teams, int left, int mid, int right) {
int i = left, j = mid + 1, k = 0;
vector<Team> temp(right - left + 1);
while (i <= mid && j <= right) {
if (teams[i].id <= teams[j].id) {
temp[k++] = teams[i++];
}
else {
temp[k++] = teams[j++];
}
}
while (i <= mid) {
temp[k++] = teams[i++];
}
while (j <= right) {
temp[k++] = teams[j++];
}
for (i = 0; i < k; i++) {
teams[left + i] = temp[i];
}
}
void mergeSort(vector<Team>& teams, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(teams, left, mid);
mergeSort(teams, mid + 1, right);
merge(teams, left, mid, right);
}
}
void queryTeam1(vector<Team>& teams) {
string category;
cout << "请输入要查询的赛事类别:" << endl;
cin >> category;
// 归并排序
mergeSort(teams, 0, teams.size() - 1);
// 输出排序后的参赛队信息
for (int i = 0; i < teams.size(); i++) {
if (teams[i].category == category) {
Team team = teams[i];
cout << "编号:" << team.id << endl;
cout << "作品名称:" << team.name << endl;
cout << "学校:" << team.school << endl;
cout << "类别:" << team.category << endl;
cout << "参赛者:" << team.members << endl;
cout << "指导老师:" << team.teacher << endl;
}
}
}
void addTeam(vector<Team>& teams) {
Team team;
cout << "请输入参赛队伍信息:" << endl;
cout << "编号:";
cin >> team.id;
cout << "作品名称:";
cin >> team.name;
cout << "学校:";
cin >> team.school;
cout << "类别:";
cin >> team.category;
cout << "参赛者:";
cin >> team.members;
cout << "指导老师:";
cin >> team.teacher;
teams.push_back(team);
cout << "添加成功!" << endl;
}
// 删除参赛队伍信息
void deleteTeam(vector<Team>& teams) {
int id;
cout << "请输入要删除的参赛队伍编号:";
cin >> id;
for (auto it = teams.begin(); it != teams.end(); it++) {
if (it->id == to_string(id)) {
teams.erase(it);
cout << "删除成功!" << endl;
return;
}
}
cout << "未找到该参赛队伍!" << endl;
}
// 修改参赛队伍信息
void modifyTeam(vector<Team>& teams) {
int id;
cout << "请输入要修改的参赛队伍编号:";
cin >> id;
for (auto& team : teams) {
if (team.id == to_string(id)) {
cout << "请输入新的参赛队伍信息:" << endl;
cout << "作品名称:";
cin >> team.name;
cout << "学校:";
cin >> team.school;
cout << "类别:";
cin >> team.category;
cout << "参赛者:";
cin >> team.members;
cout << "指导老师:";
cin >> team.teacher;
return;
}
}
cout << "未找到该参赛队伍!" << endl;
}
// 将参赛队伍信息写入文件
void writeToFile(const vector<Team>& teams, const string& filename) {
ofstream outfile(filename);
if (outfile.is_open()) {
for (const auto& team : teams) {
outfile << team.id << "\t#\t" << team.name << "\t#\t" << team.school << "\t#\t" << team.category << "\t#\t" << team.members << "\t#\t" << team.teacher << endl;
}
outfile.close();
cout << "参赛队伍信息已写入文件 " << filename << " 中!" << endl;
}
else {
cout << "无法打开文件 " << filename << "!" << endl;
}
}
// 定义决赛室结构体
struct Room {
int id; // 决赛室编号
queue<Team> teams; // 参赛队队列
};
// 定义全局变量
const int NUM_ROOMS = 9; // 决赛室数量
Room rooms[NUM_ROOMS]; // 决赛室数组
void call_teams() {
// 循环遍历所有决赛室
for (int i = 0; i < NUM_ROOMS; ++i) {
// 当前决赛室
Room& room = rooms[i];
// 当前决赛室队列不为空时,循环叫号
while (!room.teams.empty()) {
// 输出叫号信息
cout << "决赛室" << room.id << "请题目为:" << room.teams.front().name << "参赛队进场比赛" << endl;
// 模拟参赛队进场比赛0.5秒
this_thread::sleep_for(chrono::milliseconds(5));
// 弹出队首元素
room.teams.pop();
}
}
}
void add_team(vector<Team>& teams)
{
// 定义需要用到的变量和常量
char strs1[3][20] = { {"大数据实践"} };
char strs2[4][30] = { {"信息图形设计"}, {"动态信息影像(MG动画)"}, {"交互信息设计"}, {"数据可视化"} };
char strs3[4][30] = { {"人工智能实践赛"} };
char strs4[5][30] = { {"Web应用与开发"}, {"管理信息系统 "}, {"算法设计与应用"}, {"移动应用开发"} };
char strs5[5][30] = { {"医药卫生"}, {"数字生活"}, {"运动健身 "}, {"城市管理 "}, {"行业应用"} };
char strs6[5][30] = { {"动画"}, {"纪录片"}, {"数字短片"}, {"微电影 "}, {"新媒体漫画"} };
char strs7[5][30] = { {"产品设计"}, {"环境设计"}, {"平面设计"} };
char strs8[5][30] = { {"交互媒体设计"}, {"游戏设计"}, {"虚拟现实VR与增强现实AR"} };
char strs9[5][50] = { {"汉语言文学"}, {"计算机基础与应用类课程微课"}, {"虚拟实验平台"}, {"中、小学数学或自然科学课程微课"} };
// 将strs存入一个vector中,方便遍历
vector<const char*> strs;
strs.insert(strs.end(), strs1, strs1 + 1);
strs.insert(strs.end(), strs2, strs2 + 4);
strs.insert(strs.end(), strs3, strs3 + 1);
strs.insert(strs.end(), strs4, strs4 + 4);
strs.insert(strs.end(), strs5, strs5 + 5);
strs.insert(strs.end(), strs6, strs6 + 5);
strs.insert(strs.end(), strs7, strs7 + 3);
strs.insert(strs.end(), strs8, strs8 + 3);
strs.insert(strs.end(), strs9, strs9 + 4);
// 定义队列
queue<Team> q1, q2, q3, q4, q5, q6, q7, q8, q9;
mergeSort(teams, 0, teams.size() - 1);
// 遍历teams,将相同category的team加入相应的队列
for (int i = 0; i < teams.size(); ++i) {
const char* category = teams[i].category.c_str();
for (int j = 0; j < strs.size(); ++j) {
if (strcmp(category, strs[j]) == 0) {
if (j==0)
q1.push(teams[i]);
else if(j>0 && j<=4)
q2.push(teams[i]);
else if (j > 4 && j <=5 )
q3.push(teams[i]);
else if (j > 5 && j <= 9)
q4.push(teams[i]);
else if (j > 9 && j <= 14)
q5.push(teams[i]);
else if (j > 14 && j <= 19)
q6.push(teams[i]);
else if (j > 19 && j <= 22)
q7.push(teams[i]);
else if (j > 22 && j <= 25)
q8.push(teams[i]);
else if (j > 25 && j <=29)
q9.push(teams[i]);
}
}
}
// 将队列存入全局变量的rooms数组中
rooms[0] = { 1, q1 };
rooms[1] = { 2, q2 };
rooms[2] = { 3, q3 };
rooms[3] = { 4, q4 };
rooms[4] = { 5, q5 };
rooms[5] = { 6, q6 };
rooms[6] = { 7, q7 };
rooms[7] = { 8, q8 };
rooms[8] = { 9, q9 };
}
// 定义无穷大常量INF,用于表示路径长度的上限
const int INF = numeric_limits<int>::max();
// Dijkstra算法实现
void dijkstra(vector<vector<pair<int, int>>>& adjList, int start, int end, vector<string>& names, vector<string>& descriptions) {
int n = adjList.size();
// 定义距离数组dist和前驱数组prev
vector<int> dist(n, INF);
vector<int> prev(n, -1);
// 将起点的距离设为0
dist[start] = 0;
// 定义优先队列pq,用于存储待处理的节点
// 优先队列中存储节点到起点的距离和节点编号,按距离从小到大排序
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push(make_pair(0, start));
// 循环处理待处理的节点,直到队列为空
while (!pq.empty()) {
// 取出距离起点最近的节点
int u = pq.top().second;
pq.pop();
// 遍历该节点的邻居节点
for (auto v : adjList[u]) {
// 计算该邻居节点到起点的距离
int alt = dist[u] + v.second;
// 如果新的距离比原来的距离更短,则更新距离和前驱节点
if (alt < dist[v.first]) {
dist[v.first] = alt;
prev[v.first] = u;
// 将该邻居节点加入优先队列
pq.push(make_pair(dist[v.first], v.first));
}
}
}
// 如果终点的距离为无穷大,则表示没有可达路径
if (dist[end] == INF) {
cout << "No path found" << endl;
}
else {
// 输出最短路径的长度
cout << "Shortest path length: " << dist[end] << endl;
// 输出最短路径的节点序列
cout << "Path: ";
vector<int> path;
int cur = end;
while (cur != -1) {
path.push_back(cur);
cur = prev[cur];
}
for (int i = path.size() - 1; i >= 0; i--) {
cout << names[path[i]] << " ";
}
cout << endl;
// 输出终点的名称和描述
cout << "Destination: " << names[end] << endl;
cout << "Description: " << descriptions[end] << endl;
}
}
int main()
{
readTeamsFromFile("C://Users//123//source//repos//ds2//team.txt");
vector<Team> teams = readTeamsFromFile("C://Users//123//source//repos//ds2//team.txt");
// 构建二叉排序树
Node* root = buildBST(teams);
string filename = "new_teams.txt";
string id;// 输入要查询的参赛队编号
int count = 0; // 统计查找次数
int sum = 0; // 统计查找次数的总和
int depth = 1;
int depthSum = 0;
int n = 20;
vector<vector<pair<int, int>>> adjList(n); // 创建大小为 n 的邻接表
vector<string> names = { "", "三号组团", "西苑食堂", "明德楼", "文体中心a", "西操场", "文理大楼", "行政大楼", "求索园", "东苑食堂", "图书馆" };
vector<string> descriptions = { "", "学生住宿地方原49号楼", "学校西边的食堂", "教学楼,对应校训的笃学明德中的明德", "学生的体育运动中心", "学校靠西边的操场", "江科大最高的一栋楼", "行政教学用地", "花园", "学校西边的食堂", "读书学习的地方" };
adjList[1].push_back(make_pair(2, 100)); // 添加从节点 1 到节点 2 权值为 100 的边
adjList[1].push_back(make_pair(4, 200)); // 添加从节点 1 到节点 4 权值为 200 的边
adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
adjList[2].push_back(make_pair(4, 150)); // 添加从节点 2 到节点 4 权值为 150 的边
adjList[2].push_back(make_pair(3, 80)); // 添加从节点 2 到节点 3 权值为 80 的边
adjList[3].push_back(make_pair(2, 80)); // 添加从节点 3 到节点 2 权值为 80 的边
adjList[3].push_back(make_pair(5, 120)); // 添加从节点 3 到节点 5 权值为 120 的边
adjList[3].push_back(make_pair(6, 110)); // 添加从节点 3 到节点 6 权值为 110 的边
adjList[4].push_back(make_pair(1, 200)); // 添加从节点 4 到节点 1 权值为 200 的边
adjList[4].push_back(make_pair(2, 150)); // 添加从节点 4 到节点 2 权值为 150 的边
adjList[4].push_back(make_pair(5, 50)); // 添加从节点 4 到节点 5 权值为 50 的边
adjList[5].push_back(make_pair(3, 120)); // 添加从节点 5 到节点 3 权值为 120 的边
adjList[5].push_back(make_pair(4, 50)); // 添加从节点 5 到节点 4 权值为 50 的边
adjList[5].push_back(make_pair(8, 150)); // 添加从节点 5 到节点 8 权值为 150 的边
adjList[5].push_back(make_pair(9, 230)); // 添加从节点 5 到节点 9 权值为 230 的边
adjList[6].push_back(make_pair(3, 110)); // 添加从节点 6 到节点 3 权值为 110 的边
adjList[6].push_back(make_pair(7, 80)); // 添加从节点 6 到节点 7 权值为 80 的边
adjList[6].push_back(make_pair(8, 60)); // 添加从节点 6 到节点 8 权值为 80 的边
adjList[7].push_back(make_pair(6, 80)); // 添加从节点 7 到节点 6 权值为 80 的边
adjList[7].push_back(make_pair(10, 100)); // 添加从节点 7 到节点 10 权值为 100 的边
adjList[8].push_back(make_pair(5, 150)); // 添加从节点 8 到节点 5 权值为 150 的边
adjList[8].push_back(make_pair(6, 60)); // 添加从节点 8 到节点 6 权值为 60 的边
adjList[8].push_back(make_pair(9, 90)); // 添加从节点 8 到节点 9 权值为 90 的边
adjList[8].push_back(make_pair(10, 70)); // 添加从节点 8 到节点 10 权值为 70 的边
adjList[9].push_back(make_pair(5, 230)); // 添加从节点 9 到节点 5 权值为 230 的边
adjList[9].push_back(make_pair(8, 90)); // 添加从节点 9 到节点 8 权值为 90 的边
adjList[9].push_back(make_pair(10, 50)); // 添加从节点 9 到节点 10 权值为 50 的边
adjList[10].push_back(make_pair(7, 100)); // 添加从节点 10 到节点 7 权值为 100 的边
adjList[10].push_back(make_pair(8, 70)); // 添加从节点 10 到节点 8 权值为 70 的边
adjList[10].push_back(make_pair(9, 50)); // 添加从节点 10 到节点 9 权值为 50 的边
int m = 0;
char choice;
while (true) {
cout << "请选择操作:" << endl;
cout << "1. 添加参赛队伍信息" << endl;
cout << "2. 删除参赛队伍信息" << endl;
cout << "3. 修改参赛队伍信息" << endl;
cout << "4. 按编号查询参赛团队 " << endl;
cout << "5. 按参加类别查询参赛团队" << endl;
cout << "6. 叫号系统" << endl;
cout << "7. 导航系统" << endl;
cout << "8. 退出程序" << endl;
cout << "请输入操作编号:";
cin >> choice;
switch (choice) {
case '1':
addTeam(teams);
break;
case '2':
deleteTeam(teams);
break;
case '3':
modifyTeam(teams);
break;
case '4':
{
cout << "请输入要查询的参赛队编号:" << endl;
cin >> id;
bool found = queryTeam(root, id); // 在二叉排序树中查找指定编号的参赛队信息
traverseBST(root, depth, count, depthSum);
if (found) {
cout << "ASL = depthSum / count" << endl;
// 输出平均查找长度ASL
double ASL = (double)depthSum / count;
cout << count;
cout << "查找成功!" << endl;
cout << "平均查找长度ASL:" << ASL << endl;
}
else {
cout << "查找失败!" << endl;
}
break; }
case '5':
queryTeam1(teams);
break;
case '6':
add_team(teams);
call_teams();
break;
case '7':
for (int i = 0; i < n; i++) {
m += adjList[i].size();
}
cout << "The number of edges is: " << m << endl;
cout << "编号从1开始到10分别是1:三号组团, 2:西苑食堂,3: 明德楼, 4:文体中心a, 5:西操场, 6:文理大楼, 7:行政大楼, 8:求索园, 9:东苑食堂,10: 图书馆" << endl;
cout << "输入起始序号和终点序号" << endl;
int start, end;
cin >> start >> end;
if (start < 0 || start >= n || end < 0 || end >= n) {
cout << "Invalid input" << endl;
return 0;
}
dijkstra(adjList, start, end, names, descriptions);
break;
case '8':
writeToFile(teams, filename);
return 0;
default:
cout << "无效的操作编号,请重新输入!" << endl;
break;
}
}
return 0;
}