课程设计预习日志(赛事管理系统)

2023-12-16 02:20

本文主要是介绍课程设计预习日志(赛事管理系统),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、设计内容

       中国大学生计算机设计大赛是我国高校面向本科生的计算机应用设计大赛,大赛旨在激发学生学习计算机知识和技能的兴趣与潜能,提高学生运用信息技术解决实际问题的综合能力。通过大赛这种计算机教学实践形式,可展示师生的教与学成果,最终以赛促学,以赛促教,以赛促创。该赛事在历届学生中影响力较大,参与者众多,请结合2021届省赛参赛的数据,借助数据结构课程所学的相关知识,通过对数据的处理和分析,熟悉数据结构设计及数据处理在信息管理系统中应用的重要性。赛事相关数据存储在文本文件和excel文件中,相应的文件信息说明如表1所示。其中,各个文件中不同的数据项之间均使用#分隔,图1中给出了文件team.txt中参赛信息的对应数据示例。

                      图1. 参赛队基本信息

【问题描述】

       本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:

(1)能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括增加、删除、修改参赛队伍的信息。

(2)从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
(3)能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)

(4)为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)

(5)赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。


二、设计要求

1)赛事数据要求存入文件(txt或excel)并能读入查询;

2)赛地目的地查询,需提供目的地(建筑物)名称、代号、简介、两地之间路径长度等信息;

3)输入数据形式和范围:赛事相关数据可从键盘输入,或自文件导入。

4)界面要求:交互设计要合理,每个功能可以设计菜单,用户根据提示,完成相关功能的要求。


三、实验过程

首先确定我们需要的头文件:

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <bits/stdc++.h>

定义参赛队伍结构体:

//节点
typedef struct TeamNode {int number;               //参赛队伍编号string name;              //作品名称string school;            //参赛队伍学校string category;          //赛事类别string contestant;        //参赛者string teacher;           //指导老师struct TeamNode *lchild;  //左孩子struct TeamNode *rchild;  //右孩子
} TeamNode;

定义地点节点结构体:

//地点节点
struct Site {char name[10];            //地点名称char introduce[100];      //地点介绍
} s[12];

需要用到的功能函数:

void Menu();       //菜单
void ReadTeams();  //读取参赛队伍信息
void AddTeam();    //增添参赛队伍信息
void DeleteTeam(); //删除参赛队伍信息
void EditTeam();   //修改参赛队伍信息
void Lookup_num(); //按参赛队编号查找
void Lookup_sch(); //按参赛学校查询
void Call();       //决赛叫号模拟
void Guide();      //校园导游服务
void PrintTeams(); //打印
void Save();       //保存
void Remove(string &s);                           //去除字符串中的空格
void Insert(TeamNode **T, int number, string name, string school, string category, string contestant,string teacher);                      //插入二叉排序树
TeamNode *SearchParent(TeamNode *T, int number);  //寻找父节点
TeamNode *Search(TeamNode *T, int number);        //基于二叉排序树的查找
void Inorder(TeamNode *T);                        //中序遍历二叉排序树
void Inorder2(TeamNode *T, string school);        //中序遍历二叉排序树进行有条件的输出
int Totalweight(TeamNode *T, int d);              //计算总权值
int Node_num(TeamNode *T);                        // 计算总结点数
void Inorder3(TeamNode *T, ofstream &ofs);        //中序遍历二叉排序树将数据写入文件
void Inorder4(TeamNode *T, int *t, int &index);   //遍历生成存储参赛队编号的数组,并返回指向该数组的指针
void Siteslist();                                 //地点列表
void Store();                                     //存储景点信息、同时存图,各边信息
void Dijkstra(int v0, int t);                     //迪杰斯特拉求最短路径,并输出路线

       将以上以上代码放入我们的头文件“ManageSystem.h”中,完整的头文件“ManageSystem.h”内容如下:

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
#define inf 99999999
using namespace std;
int road_map[20][20], book[20], dis[20];//节点
typedef struct TeamNode {int number;               //参赛队伍编号string name;              //作品名称string school;            //参赛队伍学校string category;          //赛事类别string contestant;        //参赛者string teacher;           //指导老师struct TeamNode *lchild;  //左孩子struct TeamNode *rchild;  //右孩子
} TeamNode;TeamNode *T = NULL;//地点节点
struct Site {char name[10];            //地点名称char introduce[100];      //地点介绍
} s[12];void Menu();       //菜单
void ReadTeams();  //读取参赛队伍信息
void AddTeam();    //增添参赛队伍信息
void DeleteTeam(); //删除参赛队伍信息
void EditTeam();   //修改参赛队伍信息
void Lookup_num(); //按参赛队编号查找
void Lookup_sch(); //按参赛学校查询
void Call();       //决赛叫号模拟
void Guide();      //校园导游服务
void PrintTeams(); //打印
void Save();       //保存
void Remove(string &s);                           //去除字符串中的空格
void Insert(TeamNode **T, int number, string name, string school, string category, string contestant,string teacher);                      //插入二叉排序树
TeamNode *SearchParent(TeamNode *T, int number);  //寻找父节点
TeamNode *Search(TeamNode *T, int number);        //基于二叉排序树的查找
void Inorder(TeamNode *T);                        //中序遍历二叉排序树
void Inorder2(TeamNode *T, string school);        //中序遍历二叉排序树进行有条件的输出
int Totalweight(TeamNode *T, int d);              //计算总权值
int Node_num(TeamNode *T);                        // 计算总结点数
void Inorder3(TeamNode *T, ofstream &ofs);        //中序遍历二叉排序树将数据写入文件
void Inorder4(TeamNode *T, int *t, int &index);   //遍历生成存储参赛队编号的数组,并返回指向该数组的指针
void Siteslist();                                 //地点列表
void Store();                                     //存储景点信息、同时存图,各边信息
void Dijkstra(int v0, int t);                     //迪杰斯特拉求最短路径,并输出路线

       本系统是基于二叉排序树实现的参赛队伍信息管理系统。程序提供了多个功能,包括增加、删除、修改、查找等操作,并使用了文件存储来实现持久化存储。其中,插入和查找操作使用了递归函数进行实现,详细的遍历算法也得到了充分考虑。此外,还提供了校园导游服务和Dijkstra算法求最短路径的功能。程序考虑了复杂的图论算法,并优化了存储结构以提高效率。总的来说,本程序稳定性较高,具有比较完善的功能和良好的用户体验。

1.用户菜单界面

简单通过使用printf函数及‘\t’实现我们的菜单界面。

void Menu() {printf("*****************************************\n");printf("*\t欢迎使用赛事管理系统v1.0\t*\n");printf("*****************************************\n");printf("*\t请选择功能列表\t\t\t*\n");printf("*****************************************\n");printf("*\t1.读取参赛队伍信息\t\t*\n");printf("*\t2.增添参赛队伍信息\t\t*\n");printf("*\t3.删除参赛队伍信息\t\t*\n");printf("*\t4.修改参赛队伍信息\t\t*\n");printf("*\t5.按参赛队编号查找\t\t*\n");printf("*\t6.按参赛学校查询\t\t*\n");printf("*\t7.决赛叫号模拟\t\t\t*\n");printf("*\t8.校园导游服务\t\t\t*\n");printf("*\t9.保存\t\t\t\t*\n");printf("*\tp.打印参赛队伍信息\t\t*\n");printf("*\t0.退出系统\t\t\t*\n");printf("*****************************************\n");
}

运行结果如图所示:

 2.读取参赛队伍信息:

       该程序目的是实现从team.txt文件中读取信息。其中,函数ReadTeams()是读取参赛队伍信息的核心函数,它能够从文本文件中读取每个参赛队伍的相关信息,并将其插入到二叉排序树中。以下是该函数的具体实现过程:

  1. 打开文件 首先,这段代码使用ifstream打开名为“team.txt”的文本文件。如果打开失败,则输出失败提示信息并返回。

  2. 逐行读取文件内容 然后,该函数使用getline()函数逐行读取文件内容,将每个参赛队伍的信息存储在一个string变量str中。

  3. 去除字符串中的空格和制表符 在读取每一行之前,函数Remove()会将字符串中的空格和制表符去除。这样可以确保正确读取每个字段的值。

  4. 提取每个字段的值并插入到二叉排序树中 接下来,该函数对每一行分别使用循环进行遍历,通过找到“#”字符将该行信息分成6个字段。然后,将各个字段的值(如参赛队伍编号、名称、所属学校等)分别存储在相应的变量中。

  5. 最后,调用Insert()函数,将该参赛队伍的信息以二叉排序树节点的形式插入到二叉排序树中。该节点的结构为TeamNode,其中包含参赛队伍编号、名称、所属学校、类别、参赛者、指导老师等信息。

  6. 输出读取成功信息并清空控制台屏幕读取文件完成后,函数输出“读取成功”的提示信息,并等待用户按下任意键继续下一步操作。同时,还会清空控制台屏幕,以便用户能够更清晰地看到每个功能的执行结果。

代码如下:

//去除字符串中的空格
void Remove(string &s) {string::size_type index = 0;if (!s.empty()) {while ((index = s.find('\t', index)) != string::npos) { // 进行转行 ,不然无法清除s.erase(index, 1);}}
}//插入二叉排序树
void Insert(TeamNode **T, int number, string name, string school, string category, string contestant, string teacher) {if (*T == NULL) {*T = new TeamNode();(*T)->number = number;(*T)->name = name;(*T)->school = school;(*T)->category = category;(*T)->contestant = contestant;(*T)->teacher = teacher;(*T)->lchild = NULL;(*T)->rchild = NULL;} else if (number < (*T)->number) {Insert(&((*T)->lchild), number, name, school, category, contestant, teacher);} else if (number > (*T)->number) {Insert(&((*T)->rchild), number, name, school, category, contestant, teacher);}
}//读取参赛队伍信息
void ReadTeams() {//打开文件ifstream fp;fp.open("team.txt");if (!fp) {printf("打开文件失败!\n");return;}//读文件string str;int number;string name, school, category, contestant, teacher;while (getline(fp, str)) {if (str[0] != '2')continue;Remove(str);for (int i = 0; i < 6; i++) {int position = str.find('#');string s = str.substr(0, position);str = str.substr(position + 1);switch (i) {case 0:number = stoi(s);break;case 1:name = s;break;case 2:school = s;break;case 3:category = s;break;case 4:contestant = s;break;case 5:teacher = s;break;default:break;}}Insert(&T, number, name, school, category, contestant, teacher);}fp.close();printf("读取成功!\n");system("pause");system("cls");
}

 3.增添参赛队伍信息

       核心函数为AddTeam(),其功能是增添一个参赛队伍到已有的参赛队伍信息列表中。该函数由以下几个步骤组成:

  1. 定义需要填写的参赛队伍信息变量 该函数在一开始定义了6个变量,分别代表参赛队伍编号、作品名称、学校、赛事类别、参赛者和指导老师的姓名。这些变量用于存储用户通过控制台输入的相应参赛队伍信息。

  2. 提示用户输入相关信息 该函数随后将逐条提醒用户输入参赛队伍的各项信息,包括参赛队编号、作品名称、学校、赛事类别、参赛者姓名和指导老师姓名等。

  3. 将信息插入到参赛队伍信息列表中 当用户输入完所有信息以后,Insert()函数会被调用,将用户刚输入的信息以二叉排序树节点的形式插入到参赛队伍信息列表中。插入完成后,该函数输出“参赛队信息增添完成”的提示信息。

  4. 等待并清空控制台屏幕 最后,该函数使用system()函数先暂停并等待用户任意键,然后再通过system("cls")清空控制台窗口,以便用户可以更清晰地看到后续执行的操作结果。

代码如下: 

//增添参赛队伍信息
void AddTeam() {int number;  //参赛队伍编号string name;   //作品名称string school; //参赛队伍学校string category;//赛事类别string contestant;//参赛者string teacher;   //指导老师printf("请输入参赛队编号:\n");cin >> number;printf("请输入参赛作品名称:\n");cin >> name;printf("请输入参赛学校:\n");cin >> school;printf("请输入赛事类别:\n");cin >> category;printf("请输入参赛者姓名:\n");cin >> contestant;printf("请输入指导老师姓名:\n");cin >> teacher;Insert(&T, number, name, school, category, contestant, teacher);printf("参赛队信息增添完成.\n");system("pause");system("cls");
}

3.删除参赛队伍信息

       这段代码实现了一个参赛队伍信息的删除功能,包含了寻找父节点函数 SearchParent 和删除函数 Delete。具体流程如下:

       首先在定义工作指针 P 的情况下,通过 while 循环扫描二叉搜索树 T 直到找到待删除的节点 P 或 P 不存在;如果没有找到则提示结点不存在。

       当找到待删除的节点 P 后,有三种情况需要考虑:

  1. 当该结点是叶子结点时,直接删除(将其父节点的左/右孩子置空);
  2. 当该结点有一个左孩子或者一个右孩子时,让其孩子结点代替它的位置;
  3. 当左右孩子都存在时找中序遍历的上一个结点(即最大值的前继或最小值的后继)代替其位置。

第三种情况需要执行以下步骤:

  1. 定义工作指针 Q 指向 P 的左孩子;
  2. 找到 Q 的右子树中的最大值,并记录 Pre2 为最终遍历到的结点 Q 的前序结点,用于后期连接;
  3. 将 Q 的值复制到 P 中,并将 Q 节点删除。

       最后,定义一个函数 DeleteTeam() 实现用户输入需要删除的参赛队编号,调用函数 Delete 进行删除操作,并输出删除成功信息。其中,cin 和 cout 分别实现用户输入和输出信息。系统函数 system("pause") 和 system("cls") 分别实现暂停并等待用户按任意键继续和清屏操作。

代码如下:

//寻找父节点
TeamNode *SearchParent(TeamNode *T, int number) {if (T) {if (T->lchild->number == number || T->rchild->number) {return T;} else if (number < T->number) {return SearchParent(T->lchild, number);} else {return SearchParent(T->rchild, number);}} else {return NULL;}
}void Delete(TeamNode *T, int number) {//首先找到要删除的结点TeamNode *Pre;TeamNode *P = T;                    //定义工作指针while (P != NULL && number != P->number) {if (number > P->number) {Pre = P;P = P->rchild;} else {Pre = P;P = P->lchild;}}if (P == NULL) {printf("要删除的结点不存在.\n" );} else {// 当该结点是叶子结点时,直接删除if (P->lchild == NULL && P->rchild == NULL) {if (P->number > Pre->number) {Pre->rchild = NULL;} else {Pre->lchild = NULL;}}//当该结点有一个左孩子或者一个右孩子时,让其孩子结点代替他的位置if ((P->lchild != NULL && P->rchild == NULL) || (P->rchild != NULL && P->lchild == NULL)) {if (P->number > Pre->number) {if (P->lchild != NULL) {Pre->rchild = P->lchild;} else {Pre->rchild = P->rchild;}}if (P->number < Pre->number) {if (P->lchild != NULL) {Pre->lchild = P->lchild;} else {Pre->lchild = P->rchild;}}}//当左右孩子都存在时找中序遍历的上一个结点代替其位置if (P->lchild != NULL && P->rchild != NULL) {TeamNode *Q = P->lchild;    //工作指针TeamNode *Pre2;             //用于记录最终遍历到的结点的前序结点,用于后期连接while (Q->rchild) {Pre2 = Q;Q = Q->rchild;}P->number = Q->number;P->name = Q->name;P->school = Q->school;P->category = Q->category;P->contestant = Q->contestant;P->teacher = Q->teacher;if (P != Pre2) {Pre2->rchild = Q->lchild;} else {Pre2->lchild = Q->lchild;}delete (Q);}}
}//删除参赛队伍信息
void DeleteTeam() {int number;printf("请输入需要删除的参赛队编号:\n");cin >> number;Delete(T, number);printf("该参赛队信息已删除.\n");system("pause");system("cls");
}

 4.修改参赛队伍信息

       核心函数为EditTeam(),其实现了一个参赛队伍信息的修改功能。主要流程如下:

  1. 首先,定义一个整型变量 number,需要用户输入参赛队编号;
  2. 调用 Search(T, number) 函数查找编号为 number 的参赛队,并将其返回值赋给指针变量 p。如果没查找到,则输出错误提示信息"查找不到此参赛队,请重试."。
  3. 如果查找到了,则输出提示信息让用户输入新的参赛队信息,并更新该节点的数据成员 name、school、category、contestant 和 teacher。最后输出一个提示"参赛队信息修改完成."。
  4. 在查找函数 Search(T, number) 中,参数 T 为根节点指针,number 为待查找的参赛队编号。在搜索过程中,若 T 为空,则说明未找到目标节点,返回 NULL。否则,比较待查找的编号 number 与当前节点 T 的编号大小,若相等,则返回当前节点;若 number 小于 T 的编号,则在左子树中继续查找;否则在右子树中继续查找。
  5. 在执行完修改操作后,通过 system("pause") 暂停并等待用户按任意键继续,通过 system("cls") 清屏操作来显示修改结果。

代码如下: 

//修改参赛队伍信息
void EditTeam() {int number;string name;   //作品名称string school; //参赛队伍学校string category;//赛事类别string contestant;//参赛者string teacher;   //指导老师printf("请输入需要修改信息的参赛队编号:\n");cin >> number;TeamNode *p = Search(T, number);if (p) {printf("请输入新信息\n");printf("参赛作品名称:\n");cin >> name;printf("参赛学校:\n");cin >> school;printf("赛事类别:\n");cin >> category;printf("参赛者姓名:\n");cin >> contestant;printf("指导老师姓名:\n");cin >> teacher;p->name = name;p->school = school;p->category = category;p->contestant = contestant;p->teacher = teacher;printf("参赛队信息修改完成.\n");} else {printf("查找不到此参赛队,请重试.\n");}system("pause");system("cls");
}//基于二叉排序树的查找
TeamNode *Search(TeamNode *T, int number) {if (T) {if (T->number == number) {return T;} else if (number < T->number) {return Search(T->lchild, number);} else {return Search(T->rchild, number);}} else {return NULL;}
}

5.按参赛队编号查找

       首先,定义了二叉排序树的节点数据结构 TeamNode,包括名称 name、编号 number、所属学校 school、赛事类别 category、参赛者 contestant 和指导老师 teacher 等信息。 数据结构TeamTree代表整棵二叉排序树,包含根节点指针head。

       然后,定义了函数 Search(T, number),用于在二叉排序树中按照编号 number 查找对应的节点,并返回该节点的指针。具体实现是利用递归的方法,从根节点 T 开始,若当前节点为空,则返回 NULL;若相等就返回该节点;若待查找编号小于当前节点编号,则递归查找左子树;否则递归查找右子树。

       接下来,定义了Totalweight(T, d) 和 Node_num(T) 两个函数,分别用于计算二叉排序树的总权值和总结点数。其中 Totalweight(T, d) 函数通过递归计算树的深度和每个节点的权值之和,以求得总权值;而Node_num(T) 函数通过递归遍历树的所有节点数,以求得总结点数。这两个函数可以用于后续统计和分析。

       最后,定义了 Lookup_num() 函数,实现了按编号查找参赛队伍信息的功能。函数中,首先让用户输入待查找的参赛队编号 number,然后调用上述的 Search(T, number) 函数查找对应节点,并输出该节点的相关信息。

       此外,Lookup_num() 函数还统计了二叉排序树的总权值和总结点数,并输出平均搜索长度ASL作为性能指标。最后,通过 system("pause") 暂停程序执行并等待用户按下任意键继续执行,然后通过 system("cls") 命令清空屏幕内容,以便于显示查找结果。

代码如下:

//基于二叉排序树的查找
TeamNode *Search(TeamNode *T, int number) {if (T) {if (T->number == number) {return T;} else if (number < T->number) {return Search(T->lchild, number);} else {return Search(T->rchild, number);}} else {return NULL;}
}//计算总权值
int Totalweight(TeamNode *T, int d) {d++;int a = d;if (T->lchild)d += Totalweight(T->lchild, a);if (T->rchild)d += Totalweight(T->rchild, a);return d;
}// 计算总结点数
int Node_num(TeamNode *T) {if (T == NULL) {   // 空节点判断return 0;}int d = 1 + Node_num(T->lchild) + Node_num(T->rchild);return d;
}//按参赛队编号查找
void Lookup_num() {int number, d1, d2;printf("请输入需要查找的参赛队编号:\n");cin >> number;TeamNode *p = Search(T, number);if (p != NULL) {printf("参赛队编号:%d\n参赛作品名称:%s\n参赛学校:%s\n赛事类别:%s\n参赛者:%s\n指导老师:%s\n", p->number, p->name.c_str(),p->school.c_str(), p->category.c_str(),p->contestant.c_str(), p->teacher.c_str());d1 = Totalweight(T, 0);d2 = Node_num(T);cout << "ASL=" << d1 << '/' << d2 << '=' << d1 * 1.0 / d2 << endl;} else {printf("查找失败!\n");}system("pause");system("cls");
}

6.按参赛学校查询

       按参赛学校查询的功能,使用中序遍历二叉排序树,在满足指定学校名的条件下输出符合要求的队伍信息。

       具体来说,Inorder2(T, school) 函数实现了在二叉排序树 T 中,对所有节点进行中序遍历,并按照指定条件进行输出。函数首先通过递归方法遍历左子树,然后判断当前节点的所属学校是否与参数 school 相等,如果相等就将本节点的信息输出,否则忽略本节点。最后再通过递归方法遍历右子树。需要注意的是,由于我们采用了 C++ 里的 string 类型存储学校名称,因此需要使用 c_str() 方法将其转换成 char* 类型才能直接输出。

       Lookup_sch() 函数本身很简单,它向用户输入待查询的参赛学校名,然后调用 Inorder2(T, school) 函数对所有符合条件的节点进行输出。最后,程序通过 system("pause") 和 system("cls") 命令暂停和清空屏幕,使用户能够看到查询结果。

代码如下:

//中序遍历二叉排序树进行有条件的输出
void Inorder2(TeamNode *T, string school) {if (T) {Inorder2(T->lchild, school);if (school == T->school) {printf("%d # %s # %s # %s # %s # %s\n", T->number, T->name.c_str(), T->school.c_str(), T->category.c_str(),T->contestant.c_str(), T->teacher.c_str());}Inorder2(T->rchild, school);}
}//按参赛学校查询
void Lookup_sch() {string school;printf("请输入查询的参赛学校:\n");cin >> school;system("cls");printf("参赛队编号  #  参赛作品名称  #  参赛学校  #  赛事类别  #  参赛者  #  指导老师\n");Inorder2(T, school);printf("查找完毕.\n");system("pause");system("cls");
}

 7.打印输出

       Inorder(T) 函数通过递归实现对二叉排序树 T 进行中序遍历。首先递归遍历左子树,并将其所有节点输出;然后输出本节点;再递归遍历右子树,并将其所有节点输出。由于本题所要处理的二叉排序树是按照参赛队编号从小到大排序的,因此该函数实际上就是按照编号从小到大地输出队伍信息。

       PrintTeams() 函数的作用是输出前文中构建的二叉排序树中保存的所有队伍信息。它会调用 Inorder(T) 函数对整棵树进行中序遍历,并输出所有节点的内容。打印时会在每个项目之间加入制表符 "\t" 和换行符 "\n",以便于排版。最后,程序通过 system("pause") 和 system("cls") 命令暂停和清空屏幕,使用户能够看到完整的输出结果。

 代码如下:

//中序遍历二叉排序树
void Inorder(TeamNode *T) {if (T) {Inorder(T->lchild);printf("%d # %s # %s # %s # %s # %s\n", T->number, T->name.c_str(), T->school.c_str(), T->category.c_str(),T->contestant.c_str(), T->teacher.c_str());Inorder(T->rchild);}
}//打印
void PrintTeams() {system("cls");printf("参赛队编号\t参赛作品名称\t参赛学校\t赛事类别\t参赛者\t\t指导老师\n");Inorder(T);system("pause");system("cls");
}

 8.保存信息

       Inorder3(T, ofs) 函数实现了对二叉排序树 T 进行中序遍历,并将节点信息保存到指定的文件流 ofs 中。其实现方式与 Inorder(T) 函数类似,只是输出内容的格式变成了用流对象进行输出。

       Save() 函数的作用是将前文中构建的二叉排序树中保存的所有队伍信息写入到文件 "team.txt" 中。它首先会清空文件内容,然后使用 ofstream 打开并关闭同名文件,以确保文件存在。再次打开同名文件时需要以 ios::app 模式打开,以向文件追加新的内容。接着通过 Inorder3(T, i) 函数将整棵树的信息逐一保存到文件流 i 中。最后,程序通过 system("pause") 和 system("cls") 命令暂停和清空屏幕,使用户能够看到保存结果。需要注意的是,在调用 ofstream 的 open 方法时应该先检查相关文件是否打开成功,避免出现无法打开文件的错误。

代码如下:

//中序遍历二叉排序树将数据写入文件
void Inorder3(TeamNode *T, ofstream &ofs) {if (T) {Inorder3(T->lchild, ofs);ofs << T->number << " # "<< T->name << " # "<< T->school << " # "<< T->category << " # "<< T->contestant << " # "<< T->teacher << '\n';Inorder3(T->rchild, ofs);}
}//保存
void Save() {//清空文件内容ofstream ofs("team.txt");if (!ofs) {printf("打开文件失败!\n");return;}ofs << "参赛队编号  #  参赛作品名称  #  参赛学校  #  赛事类别  #  参赛者  #  指导老师\n";ofs.close();//重新加载数据到文件中ofstream i("team.txt", ios::app);if (!i) {printf("打开文件失败!\n");return;}Inorder3(T, i);i.close();printf("保存成功!\n");system("pause");system("cls");
}

9.模拟叫号系统

       该代码段实现了一个名为 Call() 的函数用于模拟叫号系统,即依次输出所有参赛队伍的编号以及将其分配到8个决赛室中。

       Inorder4(T, t, index) 函数用于遍历二叉排序树 T,并将存储队伍编号的数组 t 进行初始化。它采用了与 Inorder3(T, ofs) 函数类似的方式进行中序遍历,并使用参数 index 来记录已经存放的索引值,并在每经过一个节点时将其编号存放到数组 t 中。

       Call() 函数首先清空屏幕和设置一些初值。然后定义一个大小为1000的动态整型数组t来存储所有队伍的编号。节点数通过 Node_num(T) 函数进行获取。接着,调用 Inorder4(T, t, index) 将所有队伍的编号复制到数组 t 中。最后,在 while 循环中对每个数组元素依次输出到不同的决赛室(共9个,索引从0-8),并在每个队伍编号之间加上对应的“决赛室”信息。这里采取了特判的方法输出,当已经输出完某个决赛室的队伍后,若还有剩余队伍,则跳转至下一个决赛室继续输出。如果当前时间的分钟小于等于8,则分钟加1;否则分钟归零,小时加1,然后输出下一个队伍。最后暂停程序并清空屏幕。

代码如下:

//遍历生成存储参赛队编号的数组,并返回指向该数组的指针
void Inorder4(TeamNode *T, int *t, int &index) {if (T) {Inorder4(T->lchild, t, index);t[index++] = T->number;Inorder4(T->rchild, t, index);}
}//模拟叫号系统
void Call() {system("cls");int index = 0;int h = 8, m = 0, k = 0, i = 0;int *t = new int[1000];int d = Node_num(T);Inorder4(T, t, index);while (i < d) {printf("%d:%d%d\n", h, k, m);printf("1号决赛室:%d\n", t[i++]);if (i == d)break;printf("2号决赛室:%d\n", t[i++]);if (i == d)break;printf("3号决赛室:%d\n", t[i++]);if (i == d)break;printf("4号决赛室:%d\n", t[i++]);if (i == d)break;printf("5号决赛室:%d\n", t[i++]);if (i == d)break;printf("6号决赛室:%d\n", t[i++]);if (i == d)break;printf("7号决赛室:%d\n", t[i++]);if (i == d)break;printf("8号决赛室:%d\n", t[i++]);if (i == d)break;printf("9号决赛室:%d\n", t[i++]);if (i == d)break;if (m < 9)m++;if (m == 9) {m = 0;if (k < 5)k++;if (k == 5) {k = 0;h++;}}}delete []t;printf("模拟完成.\n");system("pause");system("cls");
}

10.校园导游服务

       函数 Guide() 实现了一个校园导游服务。该函数首先展示了景点信息,然后让用户选择功能。当用户选择第一项时,程序要求用户输入一个地点编号,然后输出该地点名称和介绍等信息,并结束执行;当用户选择第二项时,程序要求用户输入起点和终点景点编号,接着使用 Dijkstra 算法求解从起点到终点的最短路径,并输出路径和距离。

对于 Dijkstra 算法,它是一种基于贪心策略实现的单源最短路径算法。在代码中,Dijkstra 函数首先初始化距离数组 dis 和节点数组 p。其中,dis[i] 表示从起点到节点 i 的当前最短路径长度,p[i] 记录节点 i 在最短路径中的前一节点。这两个数组都有初始值,其中 dis[v0] 的初始值为 0,表示起点到自己的距离为 0,其余部分都初始化为邻接矩阵中相应的距离,即 road_map[v0][i]

接下来,Dijkstra 函数使用一个 bool 类型的标记数组 book 来记录每个节点是否被遍历过。开始时,只有起点被标记,其他节点都未被标记。然后,Dijkstra 函数进入一个循环,在每次循环中,首先找到离起点最近的未标记节点 u,将其标记,并更新与 u 相邻的节点 v 的距离和前向星数组 p。若满足 dis[v] > dis[u] + road_map[u][v],即从起点到 u 再到 v 的距离小于当前记录的起点到 v 的距离,就更新 dis[v] 为更小值,并且将节点 u 记录为节点 v 在最短路径中的前一节点。

       最后,在 Dijkstra 函数中,使用前向星数组 p 和节点数组 s 来输出完整的最短路径,以及路径长度。具体地,首先由终点开始,按照前向星的方向逐个存储在一个中间节点数组 l 中,然后逆序输出,即得到完整的最短路径。同时,根据节点数组 s,输出每个节点的名称。

代码如下:

//地点列表
void Siteslist() {printf("*****************************************\n");printf("*\t\t地点列表\t\t*\n");printf("*****************************************\n");printf("*\t\t<1>三号组团\t\t*\n");printf("*\t\t<2>西苑食堂\t\t*\n");printf("*\t\t<3>明德园\t\t*\n");printf("*\t\t<4>文体中心\t\t*\n");printf("*\t\t<5>西田径场\t\t*\n");printf("*\t\t<6>文理大楼\t\t*\n");printf("*\t\t<7>北苑食堂\t\t*\n");printf("*\t\t<8>求索园\t\t*\n");printf("*\t\t<9>东苑食堂\t\t*\n");printf("*\t\t<10>图书馆\t\t*\n");printf("*****************************************\n");
}//存储景点信息、同时存图,各边信息
void Store() {int i, j;strcpy(s[1].name, "三号组团");strcpy(s[1].introduce, "三号组团是学生住宿楼,其中住着计算机学院的学子,他们都无比优秀。");strcpy(s[2].name, "西苑食堂");strcpy(s[2].introduce, "西苑食堂是一个供应学校师生员工用餐的场所,提供各种美食和饮品,是大家日常用餐的主要场所之一。");strcpy(s[3].name, "明德园");strcpy(s[3].introduce, "明德园环境优美、景色宜人,是人们度过悠闲时光、放松身心的理想场所。");strcpy(s[4].name, "文体中心");strcpy(s[4].introduce,"文体中心是一个综合性场所,它不仅能促进社区文化教育和艺术交流、发展体育锻炼和竞技运动,同时也能让人们更好地享受文化和娱乐生活,为学生们打造出一处智慧、和谐、幸福、美好的生活环境。");strcpy(s[5].name, "西田径场");strcpy(s[5].introduce,"田径场是一种专门用于田径运动比赛和训练的设施。通常由跑道、标准的跳远、三级跳、撑杆跳、铅球、铁饼、标枪、链球等各种田径比赛项目的比赛区域和其他辅助设施组成。");strcpy(s[6].name, "文理大楼");strcpy(s[6].introduce, "文理大楼作为江苏科技大学长山校区第一高楼,共21层,高103米,是江科大的标志性建筑。");strcpy(s[7].name, "北苑食堂");strcpy(s[7].introduce,"北苑食堂提供多样化的饮食选择,如米饭、面条、馒头、馄饨、炒菜、烧烤等,同时还提供不同口味的汤、饮料和甜点等。");strcpy(s[8].name, "求索园");strcpy(s[8].introduce, "求索园是学生们接近自然、放松身心、锻炼身体的重要场所之一。");strcpy(s[9].name, "东苑食堂");strcpy(s[9].introduce,"东苑食堂注重菜品的营养搭配和健康指导,通过设置标识或提供专门的食品展示区来提示餐品的营养成分,以便师生员工做出更加合理的用餐选择。");strcpy(s[10].name, "图书馆");strcpy(s[10].introduce,"图书馆是一种公共设施,提供各种类型的书籍、期刊和其他资料,供读者借阅或在馆内阅读。图书馆也提供其他服务,如电子资源显微镜报告、计算机终端、学习空间和教育课程。");for (i = 1; i <= 12; i++) {for (j = 1; j <= 12; j++) {if (i == j)road_map[i][j] = 0;elseroad_map[i][j] = inf;}}road_map[1][2] = 100;road_map[1][4] = 200;road_map[2][1] = 100;road_map[2][3] = 80;road_map[2][4] = 150;road_map[3][2] = 80;road_map[3][5] = 120;road_map[3][6] = 110;road_map[4][1] = 200;road_map[4][2] = 150;road_map[4][5] = 50;road_map[5][3] = 120;road_map[5][4] = 50;road_map[5][8] = 150;road_map[5][9] = 230;road_map[6][3] = 110;road_map[6][7] = 80;road_map[6][8] = 60;road_map[7][6] = 80;road_map[7][10] = 100;road_map[8][5] = 150;road_map[8][6] = 60;road_map[8][9] = 90;road_map[8][10] = 70;road_map[9][5] = 230;road_map[9][8] = 90;road_map[9][10] = 50;road_map[10][7] = 100;road_map[10][8] = 70;road_map[10][9] = 50;}//迪杰斯特拉求最短路径,并输出路线
void Dijkstra(int v0, int t) {int min, i, j, u, v;int p[20], l[20];memset(p, -1, sizeof(p));  //p 数组用于记录每个节点在最短路径中的前一节点memset(l, 0, sizeof(l));   //l 数组用于存储最短路径的中间节点memset(book, 0, sizeof(book));  //book 数组表示该节点是否被遍历过(0 表示未标记,1 表示已标记)for (i = 1; i <= 10; i++) {dis[i] = road_map[v0][i];if (dis[i] < inf)			//v0能直接到达,即上一站点为v0p[i] = v0;}book[v0] = 1;for (i = 1; i < 10; i++) {min = inf;for (j = 1; j <= 10; j++) {		//每次找出距离v0最近点if (book[j] == 0 && dis[j] < min) {min = dis[j];u = j;}}book[u] = 1;			//标记该点for (v = 1; v <= 10; v++) {if (book[v] == 0 && dis[v] > dis[u] + road_map[u][v]) {		//通过最近点更新其他边p[v] = u;					//存储更新的边,即为路线dis[v] = dis[u] + road_map[u][v];}}}v = t;i = 1;while (p[v] != v0) {		//将路线存入栈中,正序输出l[i++] = p[v];v = p[v];}printf("\n");u = i - 1;printf("路线为:\n");printf("%s--->", s[v0].name);for (i = u; i >= 1; i--)printf("%s--->", s[l[i]].name);printf("%s\n", s[t].name);printf("最短路径长度为:%d 米\n", dis[t]);
}//校园导游服务
void Guide() {system("cls");Siteslist();int opt, num, n, m;printf("欢迎使用校园导航服务,请选择功能:\n1.查询目标地信息.\n2.问路查询.\n");cin >> opt;Store();if (opt == 1) {printf("请输入地点编号:");cin >> num;printf("地点名称:%s\n地点介绍:%s\n", s[num].name, s[num].introduce);} else if (opt == 2) {printf("请输入起点景点编号:\n");scanf("%d", &n);printf("\n请输入终点景点编号:\n");scanf("%d", &m);if (n >= 1 && n <= 10 && m >= 1 && m <= 10 && n != m)Dijkstra(n, m);else {printf("输入错误,请重试!\n");}} else {printf("输入错误,请重试!\n");}system("pause");system("cls");
}

四、实验总结

       历时两星期完成了此次数据结构课程设计,一开始感觉以自己的编程能力可能完成这个还是有一点难度,但经过我在网上不断查询、不断学习,以一种边学边做的状态也是完成了此时课程设计。整体上,本次课设我是基于二叉排序树实现的,总结功能如下:

  1. 读取参赛队伍信息:将参赛队伍信息从team.txt文件中读取到系统中,然后进行后续的操作。

  2. 添加参赛队伍信息:用户可以输入参赛队伍编号、作品名称、学校、赛事类别、参赛者及指导老师等信息,然后将其插入到二叉排序树中(按编号有序排列),以便后面的查找和修改。

  3. 删除参赛队伍信息:用户可以通过输入参赛队伍编号来寻找该队的节点位置,然后将其从二叉排序树中删除。当该队信息删除成功时,程序会提示“删除成功”,否则提示“未找到该队或者已被删除”。

  4. 修改参赛队伍信息:用户可以通过输入需要更改的参赛队伍编号来寻找该队的节点位置,并输入新的信息进行更新。当该队信息修改完成后,程序会提示“修改成功”,否则提示“未找到该队”。

  5. 按参赛队编号查找:用户可以通过输入参赛队伍编号查询该队的详细信息。

  6. 按参赛学校查询:用户可以输出指定学校的所有参赛队伍信息。

  7. 决赛叫号模拟:该功能在用户输入一个时间间隔后,会每隔一段时间就随机选取下一场比赛的参赛队伍,并进行打印操作。

  8. 校园导游服务:该功能提供多个景点的介绍,并在用户输入起点和终点之后,生成一条从起点到终点的最短路径。

  9. 打印:用户可以输出全部参赛队伍信息或者筛选某个学校的所有参赛队伍信息。

  10. 保存:该系统提供将参赛队伍数据保存到文件中的功能,采用中序遍历二叉排序树的方法逐行将数据写入指定文件中。

  11. 其它辅助函数:如节点插入、寻找父节点、中序遍历、计算总权值、计算总结点数等。同时该系统还包含了图论算法Dijkstra求解最短路径问题。

       我对参赛队的数据存储采用二叉排序树(BST)结构。BST是一种有序的树形结构,在每个节点中存储着一个数据,利用每个节点的左子树小于当前节点数值、右子树大于当前节点数值的规则,可以进行快速的查找和插入/删除操作。因此,显然BST对于类似参赛队伍这样的“有序性”数据非常适合。

       在具体实现过程中,为了避免出现把某些相等节点的判断失误,采用了两个与BTS相关的同类型数据的排序依据(即按照编号升序排列、但编号如果相同按照时间先后排列),从而严谨地保证了参赛队伍数据的有序性。

       此外,该系统还引入了决赛叫号模拟和校园导游服务等功能。其中,决赛叫号模拟通过随机  选取参赛队伍来提高用户趣味性;而校园导游服务则通过Dijkstra最短路径算法,为用户提供导航指引。

       在实现过程中,我还利用了一些经典的数据结构和算法。比如,在删除节点时,采取了三重判断的方法:如果当前节点有左右子树,则需要寻找到当前节点的后继结点,并替换当前节点的值,从而实现以保证树的有序性;如果当前节点只有左子树或者右子树,则直接用需要删除的节点的子树代替即可;最后如果当前节点为叶节点时则直接删除。

       此外,在节点插入和访问操作时,我分别采用了递归和循环的不同实现方式,并通过限制二叉排序树高度,有效地避免了二叉平衡树旋转操作带来的复杂性,并兼顾空间和时间性能。

       总的来说,该参赛管理系统功能基本全部实现,满足我们的课设任务要求。

五、源码 

头文件"ManageSystem.h"源码:

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
#define inf 99999999
using namespace std;
int road_map[20][20], book[20], dis[20];//节点
typedef struct TeamNode {int number;               //参赛队伍编号string name;              //作品名称string school;            //参赛队伍学校string category;          //赛事类别string contestant;        //参赛者string teacher;           //指导老师struct TeamNode *lchild;  //左孩子struct TeamNode *rchild;  //右孩子
} TeamNode;TeamNode *T = NULL;//地点节点
struct Site {char name[10];            //地点名称char introduce[100];      //地点介绍
} s[12];void Menu();       //菜单
void ReadTeams();  //读取参赛队伍信息
void AddTeam();    //增添参赛队伍信息
void DeleteTeam(); //删除参赛队伍信息
void EditTeam();   //修改参赛队伍信息
void Lookup_num(); //按参赛队编号查找
void Lookup_sch(); //按参赛学校查询
void Call();       //决赛叫号模拟
void Guide();      //校园导游服务
void PrintTeams(); //打印
void Save();       //保存
void Remove(string &s);                           //去除字符串中的空格
void Insert(TeamNode **T, int number, string name, string school, string category, string contestant,string teacher);                      //插入二叉排序树
TeamNode *SearchParent(TeamNode *T, int number);  //寻找父节点
TeamNode *Search(TeamNode *T, int number);        //基于二叉排序树的查找
void Inorder(TeamNode *T);                        //中序遍历二叉排序树
void Inorder2(TeamNode *T, string school);        //中序遍历二叉排序树进行有条件的输出
int Totalweight(TeamNode *T, int d);              //计算总权值
int Node_num(TeamNode *T);                        // 计算总结点数
void Inorder3(TeamNode *T, ofstream &ofs);        //中序遍历二叉排序树将数据写入文件
void Inorder4(TeamNode *T, int *t, int &index);   //遍历生成存储参赛队编号的数组,并返回指向该数组的指针
void Siteslist();                                 //地点列表
void Store();                                     //存储景点信息、同时存图,各边信息
void Dijkstra(int v0, int t);                     //迪杰斯特拉求最短路径,并输出路线

系统功能源码:

#include "ManageSystem.h"int main() {while (1) {Menu();  //菜单char ch = getch();   //从键盘接受一个字符switch (ch) {case '1':     //读取参赛队伍信息ReadTeams();break;case '2':     //增添参赛队伍信息AddTeam();break;case '3':     //删除参赛队伍信息DeleteTeam();break;case '4':     //修改参赛队伍信息EditTeam();break;case '5':     //按参赛队编号查找Lookup_num();break;case '6':     //按参赛学校查询Lookup_sch();break;case '7':     //决赛叫号模拟Call();break;case '8':     //校园导游服务Guide();break;case '9':     //保存Save();break;case 'p':     //打印PrintTeams();break;case '0':     //退出系统printf("Bye Bye!\n");return 0;default:printf("您的输入有误,请重新输入.\n");system("pause");system("cls");}}return 0;
}void Menu() {printf("*****************************************\n");printf("*\t欢迎使用赛事管理系统v1.0\t*\n");printf("*****************************************\n");printf("*\t请选择功能列表\t\t\t*\n");printf("*****************************************\n");printf("*\t1.读取参赛队伍信息\t\t*\n");printf("*\t2.增添参赛队伍信息\t\t*\n");printf("*\t3.删除参赛队伍信息\t\t*\n");printf("*\t4.修改参赛队伍信息\t\t*\n");printf("*\t5.按参赛队编号查找\t\t*\n");printf("*\t6.按参赛学校查询\t\t*\n");printf("*\t7.决赛叫号模拟\t\t\t*\n");printf("*\t8.校园导游服务\t\t\t*\n");printf("*\t9.保存\t\t\t\t*\n");printf("*\tp.打印参赛队伍信息\t\t*\n");printf("*\t0.退出系统\t\t\t*\n");printf("*****************************************\n");
}//去除字符串中的空格
void Remove(string &s) {string::size_type index = 0;if (!s.empty()) {while ((index = s.find('\t', index)) != string::npos) { // 进行转行 ,不然无法清除s.erase(index, 1);}}
}//插入二叉排序树
void Insert(TeamNode **T, int number, string name, string school, string category, string contestant, string teacher) {if (*T == NULL) {*T = new TeamNode();(*T)->number = number;(*T)->name = name;(*T)->school = school;(*T)->category = category;(*T)->contestant = contestant;(*T)->teacher = teacher;(*T)->lchild = NULL;(*T)->rchild = NULL;} else if (number < (*T)->number) {Insert(&((*T)->lchild), number, name, school, category, contestant, teacher);} else if (number > (*T)->number) {Insert(&((*T)->rchild), number, name, school, category, contestant, teacher);}
}//读取参赛队伍信息
void ReadTeams() {//打开文件ifstream fp;fp.open("team.txt");if (!fp) {printf("打开文件失败!\n");return;}//读文件string str;int number;string name, school, category, contestant, teacher;while (getline(fp, str)) {if (str[0] != '2')continue;Remove(str);for (int i = 0; i < 6; i++) {int position = str.find('#');string s = str.substr(0, position);str = str.substr(position + 1);switch (i) {case 0:number = stoi(s);break;case 1:name = s;break;case 2:school = s;break;case 3:category = s;break;case 4:contestant = s;break;case 5:teacher = s;break;default:break;}}Insert(&T, number, name, school, category, contestant, teacher);}fp.close();printf("读取成功!\n");system("pause");system("cls");
}//增添参赛队伍信息
void AddTeam() {int number;  //参赛队伍编号string name;   //作品名称string school; //参赛队伍学校string category;//赛事类别string contestant;//参赛者string teacher;   //指导老师printf("请输入参赛队编号:\n");cin >> number;printf("请输入参赛作品名称:\n");cin >> name;printf("请输入参赛学校:\n");cin >> school;printf("请输入赛事类别:\n");cin >> category;printf("请输入参赛者姓名:\n");cin >> contestant;printf("请输入指导老师姓名:\n");cin >> teacher;Insert(&T, number, name, school, category, contestant, teacher);printf("参赛队信息增添完成.\n");system("pause");system("cls");
}//寻找父节点
TeamNode *SearchParent(TeamNode *T, int number) {if (T) {if (T->lchild->number == number || T->rchild->number) {return T;} else if (number < T->number) {return SearchParent(T->lchild, number);} else {return SearchParent(T->rchild, number);}} else {return NULL;}
}void Delete(TeamNode *T, int number) {//首先找到要删除的结点TeamNode *Pre;TeamNode *P = T;                    //定义工作指针while (P != NULL && number != P->number) {if (number > P->number) {Pre = P;P = P->rchild;} else {Pre = P;P = P->lchild;}}if (P == NULL) {printf("要删除的结点不存在.\n" );} else {// 当该结点是叶子结点时,直接删除if (P->lchild == NULL && P->rchild == NULL) {if (P->number > Pre->number) {Pre->rchild = NULL;} else {Pre->lchild = NULL;}}//当该结点有一个左孩子或者一个右孩子时,让其孩子结点代替他的位置if ((P->lchild != NULL && P->rchild == NULL) || (P->rchild != NULL && P->lchild == NULL)) {if (P->number > Pre->number) {if (P->lchild != NULL) {Pre->rchild = P->lchild;} else {Pre->rchild = P->rchild;}}if (P->number < Pre->number) {if (P->lchild != NULL) {Pre->lchild = P->lchild;} else {Pre->lchild = P->rchild;}}}//当左右孩子都存在时找中序遍历的上一个结点代替其位置if (P->lchild != NULL && P->rchild != NULL) {TeamNode *Q = P->lchild;    //工作指针TeamNode *Pre2;             //用于记录最终遍历到的结点的前序结点,用于后期连接while (Q->rchild) {Pre2 = Q;Q = Q->rchild;}P->number = Q->number;P->name = Q->name;P->school = Q->school;P->category = Q->category;P->contestant = Q->contestant;P->teacher = Q->teacher;if (P != Pre2) {Pre2->rchild = Q->lchild;} else {Pre2->lchild = Q->lchild;}delete (Q);}}
}//删除参赛队伍信息
void DeleteTeam() {int number;printf("请输入需要删除的参赛队编号:\n");cin >> number;Delete(T, number);printf("该参赛队信息已删除.\n");system("pause");system("cls");
}//修改参赛队伍信息
void EditTeam() {int number;string name;   //作品名称string school; //参赛队伍学校string category;//赛事类别string contestant;//参赛者string teacher;   //指导老师printf("请输入需要修改信息的参赛队编号:\n");cin >> number;TeamNode *p = Search(T, number);if (p) {printf("请输入新信息\n");printf("参赛作品名称:\n");cin >> name;printf("参赛学校:\n");cin >> school;printf("赛事类别:\n");cin >> category;printf("参赛者姓名:\n");cin >> contestant;printf("指导老师姓名:\n");cin >> teacher;p->name = name;p->school = school;p->category = category;p->contestant = contestant;p->teacher = teacher;printf("参赛队信息修改完成.\n");} else {printf("查找不到此参赛队,请重试.\n");}system("pause");system("cls");
}//基于二叉排序树的查找
TeamNode *Search(TeamNode *T, int number) {if (T) {if (T->number == number) {return T;} else if (number < T->number) {return Search(T->lchild, number);} else {return Search(T->rchild, number);}} else {return NULL;}
}//计算总权值
int Totalweight(TeamNode *T, int d) {d++;int a = d;if (T->lchild)d += Totalweight(T->lchild, a);if (T->rchild)d += Totalweight(T->rchild, a);return d;
}// 计算总结点数
int Node_num(TeamNode *T) {if (T == NULL) {   // 空节点判断return 0;}int d = 1 + Node_num(T->lchild) + Node_num(T->rchild);return d;
}//按参赛队编号查找
void Lookup_num() {int number, d1, d2;printf("请输入需要查找的参赛队编号:\n");cin >> number;TeamNode *p = Search(T, number);if (p != NULL) {printf("参赛队编号:%d\n参赛作品名称:%s\n参赛学校:%s\n赛事类别:%s\n参赛者:%s\n指导老师:%s\n", p->number, p->name.c_str(),p->school.c_str(), p->category.c_str(),p->contestant.c_str(), p->teacher.c_str());d1 = Totalweight(T, 0);d2 = Node_num(T);cout << "ASL=" << d1 << '/' << d2 << '=' << d1 * 1.0 / d2 << endl;} else {printf("查找失败!\n");}system("pause");system("cls");
}//中序遍历二叉排序树进行有条件的输出
void Inorder2(TeamNode *T, string school) {if (T) {Inorder2(T->lchild, school);if (school == T->school) {printf("%d # %s # %s # %s # %s # %s\n", T->number, T->name.c_str(), T->school.c_str(), T->category.c_str(),T->contestant.c_str(), T->teacher.c_str());}Inorder2(T->rchild, school);}
}//按参赛学校查询
void Lookup_sch() {string school;printf("请输入查询的参赛学校:\n");cin >> school;system("cls");printf("参赛队编号  #  参赛作品名称  #  参赛学校  #  赛事类别  #  参赛者  #  指导老师\n");Inorder2(T, school);printf("查找完毕.\n");system("pause");system("cls");
}//中序遍历二叉排序树
void Inorder(TeamNode *T) {if (T) {Inorder(T->lchild);printf("%d # %s # %s # %s # %s # %s\n", T->number, T->name.c_str(), T->school.c_str(), T->category.c_str(),T->contestant.c_str(), T->teacher.c_str());Inorder(T->rchild);}
}//打印
void PrintTeams() {system("cls");printf("参赛队编号\t参赛作品名称\t参赛学校\t赛事类别\t参赛者\t\t指导老师\n");Inorder(T);system("pause");system("cls");
}//中序遍历二叉排序树将数据写入文件
void Inorder3(TeamNode *T, ofstream &ofs) {if (T) {Inorder3(T->lchild, ofs);ofs << T->number << " # "<< T->name << " # "<< T->school << " # "<< T->category << " # "<< T->contestant << " # "<< T->teacher << '\n';Inorder3(T->rchild, ofs);}
}//保存
void Save() {//清空文件内容ofstream ofs("team.txt");if (!ofs) {printf("打开文件失败!\n");return;}ofs << "参赛队编号  #  参赛作品名称  #  参赛学校  #  赛事类别  #  参赛者  #  指导老师\n";ofs.close();//重新加载数据到文件中ofstream i("team.txt", ios::app);if (!i) {printf("打开文件失败!\n");return;}Inorder3(T, i);i.close();printf("保存成功!\n");system("pause");system("cls");
}//遍历生成存储参赛队编号的数组,并返回指向该数组的指针
void Inorder4(TeamNode *T, int *t, int &index) {if (T) {Inorder4(T->lchild, t, index);t[index++] = T->number;Inorder4(T->rchild, t, index);}
}//模拟叫号系统
void Call() {system("cls");int index = 0;int h = 8, m = 0, k = 0, i = 0;int *t = new int[1000];int d = Node_num(T);Inorder4(T, t, index);while (i < d) {printf("%d:%d%d\n", h, k, m);printf("1号决赛室:%d\n", t[i++]);if (i == d)break;printf("2号决赛室:%d\n", t[i++]);if (i == d)break;printf("3号决赛室:%d\n", t[i++]);if (i == d)break;printf("4号决赛室:%d\n", t[i++]);if (i == d)break;printf("5号决赛室:%d\n", t[i++]);if (i == d)break;printf("6号决赛室:%d\n", t[i++]);if (i == d)break;printf("7号决赛室:%d\n", t[i++]);if (i == d)break;printf("8号决赛室:%d\n", t[i++]);if (i == d)break;printf("9号决赛室:%d\n", t[i++]);if (i == d)break;if (m < 9)m++;if (m == 9) {m = 0;if (k < 5)k++;if (k == 5) {k = 0;h++;}}}delete []t;printf("模拟完成.\n");system("pause");system("cls");
}//地点列表
void Siteslist() {printf("*****************************************\n");printf("*\t\t地点列表\t\t*\n");printf("*****************************************\n");printf("*\t\t<1>三号组团\t\t*\n");printf("*\t\t<2>西苑食堂\t\t*\n");printf("*\t\t<3>明德园\t\t*\n");printf("*\t\t<4>文体中心\t\t*\n");printf("*\t\t<5>西田径场\t\t*\n");printf("*\t\t<6>文理大楼\t\t*\n");printf("*\t\t<7>北苑食堂\t\t*\n");printf("*\t\t<8>求索园\t\t*\n");printf("*\t\t<9>东苑食堂\t\t*\n");printf("*\t\t<10>图书馆\t\t*\n");printf("*****************************************\n");
}//存储景点信息、同时存图,各边信息
void Store() {int i, j;strcpy(s[1].name, "三号组团");strcpy(s[1].introduce, "三号组团是学生住宿楼,其中住着计算机学院的学子,他们都无比优秀。");strcpy(s[2].name, "西苑食堂");strcpy(s[2].introduce, "西苑食堂是一个供应学校师生员工用餐的场所,提供各种美食和饮品,是大家日常用餐的主要场所之一。");strcpy(s[3].name, "明德园");strcpy(s[3].introduce, "明德园环境优美、景色宜人,是人们度过悠闲时光、放松身心的理想场所。");strcpy(s[4].name, "文体中心");strcpy(s[4].introduce,"文体中心是一个综合性场所,它不仅能促进社区文化教育和艺术交流、发展体育锻炼和竞技运动,同时也能让人们更好地享受文化和娱乐生活,为学生们打造出一处智慧、和谐、幸福、美好的生活环境。");strcpy(s[5].name, "西田径场");strcpy(s[5].introduce,"田径场是一种专门用于田径运动比赛和训练的设施。通常由跑道、标准的跳远、三级跳、撑杆跳、铅球、铁饼、标枪、链球等各种田径比赛项目的比赛区域和其他辅助设施组成。");strcpy(s[6].name, "文理大楼");strcpy(s[6].introduce, "文理大楼作为江苏科技大学长山校区第一高楼,共21层,高103米,是江科大的标志性建筑。");strcpy(s[7].name, "北苑食堂");strcpy(s[7].introduce,"北苑食堂提供多样化的饮食选择,如米饭、面条、馒头、馄饨、炒菜、烧烤等,同时还提供不同口味的汤、饮料和甜点等。");strcpy(s[8].name, "求索园");strcpy(s[8].introduce, "求索园是学生们接近自然、放松身心、锻炼身体的重要场所之一。");strcpy(s[9].name, "东苑食堂");strcpy(s[9].introduce,"东苑食堂注重菜品的营养搭配和健康指导,通过设置标识或提供专门的食品展示区来提示餐品的营养成分,以便师生员工做出更加合理的用餐选择。");strcpy(s[10].name, "图书馆");strcpy(s[10].introduce,"图书馆是一种公共设施,提供各种类型的书籍、期刊和其他资料,供读者借阅或在馆内阅读。图书馆也提供其他服务,如电子资源显微镜报告、计算机终端、学习空间和教育课程。");for (i = 1; i <= 12; i++) {for (j = 1; j <= 12; j++) {if (i == j)road_map[i][j] = 0;elseroad_map[i][j] = inf;}}road_map[1][2] = 100;road_map[1][4] = 200;road_map[2][1] = 100;road_map[2][3] = 80;road_map[2][4] = 150;road_map[3][2] = 80;road_map[3][5] = 120;road_map[3][6] = 110;road_map[4][1] = 200;road_map[4][2] = 150;road_map[4][5] = 50;road_map[5][3] = 120;road_map[5][4] = 50;road_map[5][8] = 150;road_map[5][9] = 230;road_map[6][3] = 110;road_map[6][7] = 80;road_map[6][8] = 60;road_map[7][6] = 80;road_map[7][10] = 100;road_map[8][5] = 150;road_map[8][6] = 60;road_map[8][9] = 90;road_map[8][10] = 70;road_map[9][5] = 230;road_map[9][8] = 90;road_map[9][10] = 50;road_map[10][7] = 100;road_map[10][8] = 70;road_map[10][9] = 50;}//迪杰斯特拉求最短路径,并输出路线
void Dijkstra(int v0, int t) {int min, i, j, u, v;int p[20], l[20];memset(p, -1, sizeof(p));  //p 数组用于记录每个节点在最短路径中的前一节点memset(l, 0, sizeof(l));   //l 数组用于存储最短路径的中间节点memset(book, 0, sizeof(book));  //book 数组表示该节点是否被遍历过(0 表示未标记,1 表示已标记)for (i = 1; i <= 10; i++) {dis[i] = road_map[v0][i];if (dis[i] < inf)			//v0能直接到达,即上一站点为v0p[i] = v0;}book[v0] = 1;for (i = 1; i < 10; i++) {min = inf;for (j = 1; j <= 10; j++) {		//每次找出距离v0最近点if (book[j] == 0 && dis[j] < min) {min = dis[j];u = j;}}book[u] = 1;			//标记该点for (v = 1; v <= 10; v++) {if (book[v] == 0 && dis[v] > dis[u] + road_map[u][v]) {		//通过最近点更新其他边p[v] = u;					//存储更新的边,即为路线dis[v] = dis[u] + road_map[u][v];}}}v = t;i = 1;while (p[v] != v0) {		//将路线存入栈中,正序输出l[i++] = p[v];v = p[v];}printf("\n");u = i - 1;printf("路线为:\n");printf("%s--->", s[v0].name);for (i = u; i >= 1; i--)printf("%s--->", s[l[i]].name);printf("%s\n", s[t].name);printf("最短路径长度为:%d 米\n", dis[t]);
}//校园导游服务
void Guide() {system("cls");Siteslist();int opt, num, n, m;printf("欢迎使用校园导航服务,请选择功能:\n1.查询目标地信息.\n2.问路查询.\n");cin >> opt;Store();if (opt == 1) {printf("请输入地点编号:");cin >> num;printf("地点名称:%s\n地点介绍:%s\n", s[num].name, s[num].introduce);} else if (opt == 2) {printf("请输入起点景点编号:\n");scanf("%d", &n);printf("\n请输入终点景点编号:\n");scanf("%d", &m);if (n >= 1 && n <= 10 && m >= 1 && m <= 10 && n != m)Dijkstra(n, m);else {printf("输入错误,请重试!\n");}} else {printf("输入错误,请重试!\n");}system("pause");system("cls");
}

这篇关于课程设计预习日志(赛事管理系统)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/498759

相关文章

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

我在移动打工的日志

客户:给我搞一下录音 我:不会。不在服务范围。 客户:是不想吧 我:笑嘻嘻(气笑) 客户:小姑娘明明会,却欺负老人 我:笑嘻嘻 客户:那我交话费 我:手机号 客户:给我搞录音 我:不会。不懂。没搞过。 客户:那我交话费 我:手机号。这是电信的啊!!我这是中国移动!! 客户:我不管,我要充话费,充话费是你们的 我:可是这是移动!!中国移动!! 客户:我这是手机号 我:那又如何,这是移动!你是电信!!

STL经典案例(四)——实验室预约综合管理系统(项目涉及知识点很全面,内容有点多,耐心看完会有收获的!)

项目干货满满,内容有点过多,看起来可能会有点卡。系统提示读完超过俩小时,建议分多篇发布,我觉得分篇就不完整了,失去了这个项目的灵魂 一、需求分析 高校实验室预约管理系统包括三种不同身份:管理员、实验室教师、学生 管理员:给学生和实验室教师创建账号并分发 实验室教师:审核学生的预约申请 学生:申请使用实验室 高校实验室包括:超景深实验室(可容纳10人)、大数据实验室(可容纳20人)、物联网实验

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录

Detectorn2预训练模型复现:数据准备、训练命令、日志分析与输出目录 在深度学习项目中,目标检测是一项重要的任务。本文将详细介绍如何使用Detectron2进行目标检测模型的复现训练,涵盖训练数据准备、训练命令、训练日志分析、训练指标以及训练输出目录的各个文件及其作用。特别地,我们将演示在训练过程中出现中断后,如何使用 resume 功能继续训练,并将我们复现的模型与Model Zoo中的

使用Spring Boot集成Spring Data JPA和单例模式构建库存管理系统

引言 在企业级应用开发中,数据库操作是非常重要的一环。Spring Data JPA提供了一种简化的方式来进行数据库交互,它使得开发者无需编写复杂的JPA代码就可以完成常见的CRUD操作。此外,设计模式如单例模式可以帮助我们更好地管理和控制对象的创建过程,从而提高系统的性能和可维护性。本文将展示如何结合Spring Boot、Spring Data JPA以及单例模式来构建一个基本的库存管理系统

【干货分享】基于SSM的体育场管理系统的开题报告(附源码下载地址)

中秋送好礼 中秋佳节将至,祝福大家中秋快乐,阖家幸福。本期免费分享毕业设计作品:《基于SSM的体育场管理系统》。 基于SSM的体育场管理系统的开题报告 一、课题背景与意义 随着全民健身理念的深入人心,体育场已成为广大师生和社区居民进行体育锻炼的重要场所。然而,传统的体育场管理方式存在诸多问题,如资源分配不均、预约流程繁琐、数据统计不准确等,严重影响了体育场的使用效率和用户体验。

基于SSM+Vue+MySQL的可视化高校公寓管理系统

系统展示 管理员界面 宿管界面 学生界面 系统背景   当前社会各行业领域竞争压力非常大,随着当前时代的信息化,科学化发展,让社会各行业领域都争相使用新的信息技术,对行业内的各种相关数据进行科学化,规范化管理。这样的大环境让那些止步不前,不接受信息改革带来的信息技术的企业随时面临被淘汰,被取代的风险。所以当今,各个行业领域,不管是传统的教育行业

SSM项目使用AOP技术进行日志记录

本步骤只记录完成切面所需的必要代码 本人开发中遇到的问题: 切面一直切不进去,最后发现需要在springMVC的核心配置文件中中开启注解驱动才可以,只在spring的核心配置文件中开启是不会在web项目中生效的。 之后按照下面的代码进行配置,然后前端在访问controller层中的路径时即可观察到日志已经被正常记录到数据库,代码中有部分注释,看不懂的可以参照注释。接下来进入正题 1、导入m