目录
课程设计内容
中国大学生计算机设计大赛是我国高校面向本科生的计算机应用设计大赛,大赛旨在激发学生学习计算机知识和技能的兴趣与潜能,提高学生运用信息技术解决实际问题的综合能力。通过大赛这种计算机教学实践形式,可展示师生的教与学成果,最终以赛促学,以赛促教,以赛促创。该赛事在历届学生中影响力较大,参与者众多,请结合2021届省赛参赛的数据,借助数据结构课程所学的相关知识,通过对数据的处理和分析,熟悉数据结构设计及数据处理在信息管理系统中应用的重要性。赛事相关数据存储在文本文件和excel文件中,相应的文件信息说明如表1所示。其中,各个文件中不同的数据项之间均使用#分隔,图1中给出了文件team.txt中参赛信息的对应数据示例。
参赛队伍管理
【问题描述】
本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:
一、问题定义
管理各参赛队伍数据。
二、问题分析
1.能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括添加、删除、修改参赛队伍的信息。
三、主要结构设计
1.定义结点信息的数据结构,包含各参赛队的基本信息构建二叉排序树
typedef struct BiNode {
int number;
const char *offering; //参赛作品名称
const char *shoch; //参赛学校
const char *category; //赛事类别
const char *name; //参赛者
const char *teacher; //指导老师
struct BiNode* lchild, * rchild;
}BiNode,*BTree;
数据存储在.txt文件中,读取文件并提取每行中的字段数据。
public class ReadTextFile {
public static void print(List<Team> teams){
for (Team team : teams) {
System.out.println("参赛队编号: " + team.getTeamNumber());
System.out.println("参赛作品名称: " + team.getProjectName());
System.out.println("参赛学校: " + team.getSchool());
System.out.println("赛事类别: " + team.getEventCategory());
System.out.println("参赛者: " + team.getParticipant());
System.out.println("指导教师: " + team.getMentor());
System.out.println("------------------------");
}
}
public static List<Team> read(){
String fileName = "team.txt"; // 文件路径
List<Team> teams = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
String line;
boolean firstLine = true;
while ((line = br.readLine()) != null) {
if (firstLine) {
firstLine = false;
continue; // 跳过第一行标题行
}
String[] fields = line.split("#");
if (fields.length == 6) {
int teamNumber = Integer.parseInt(fields[0].trim());
String projectName = fields[1].trim();
String school = fields[2].trim();
String eventCategory = fields[3].trim();
String participant = fields[4].trim();
String mentor = fields[5].trim();
Team team = new Team(teamNumber, projectName, school, eventCategory, participant, mentor);
teams.add(team);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return teams;
}
}
构建二叉排序树
void Creat(BTree &r,int a[], int n) { //创建二叉排序树
r = NULL;
for (int i = 0; i < n; i++) {
BTree s; //= new BTree;
s->number = a[i];
s->lchild = NULL;
s->rchild = NULL;
r = Insert(r, s);
}
}
插入参赛队伍信息
BTree Insert(BTree r, BTree s) {
if (r == NULL)return s;
else
if (s->number < r->number)
r->lchild = Insert(r->lchild, s);
else
r->rchild = Insert(r->rchild, s);
return r;
}
删除参赛队伍信息
int Delete(BTree p)
{
BTree q, s;
if ((p)->rchild == NULL) //只有左子树
{
q = p;
p = (p)->lchild;
free(q);
}
else if ((p)->lchild == NULL) //只有右子树
{
q = p;
p = (p)->rchild;
free(q);
}
else //左右子树均不为空
{
q = p; s = (p)->lchild;
while (s->rchild) //找到被删结点的左子树的最右结点
{
q = s; s = s->rchild;
}
(p)->number= s->number; //此时s为被删结点的左子树的最右结点
if (q != p) //q为s 的父亲结点,此时q不重合p,也就是s不是p的右孩子
q->rchild = s->lchild;
else //此时q和p重合,s为p的右孩子
q->lchild = s->lchild;
free(s);
}
return 1;
}
基于二叉排序树的查找
从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
class BinarySearchTree { //二叉排序树
private Team root;
private int totalNodes;
private int totalComparisons;
public BinarySearchTree() {
root = null;
totalNodes = 0;
totalComparisons = 0;
}
public void insert(int teamNumber, String projectName, String school, String eventCategory,
String participant, String guideTeacher) {
root = insertNode(root, teamNumber, projectName, school, eventCategory, participant, guideTeacher);
totalNodes++;
}
private Team insertNode(Team node, int teamNumber, String projectName, String school, //插入节点
String eventCategory, String participant, String guideTeacher) {
if (node == null) {
return new Team(teamNumber, projectName, school, eventCategory, participant, guideTeacher);
}
if (teamNumber < node.getTeamNumber()) {
node.left = insertNode(node.left, teamNumber, projectName, school, eventCategory, participant, guideTeacher);
} else if (teamNumber > node.getTeamNumber()) {
node.right = insertNode(node.right, teamNumber, projectName, school, eventCategory, participant, guideTeacher);
}
return node;
}
public Team search(int teamNumber) {
totalComparisons = 0;
return searchNode(root, teamNumber);
}
private Team searchNode(Team node, int teamNumber) {
totalComparisons++;
if (node == null || node.getTeamNumber() == teamNumber) {
return node;
}
if (teamNumber < node.getTeamNumber()) {
return searchNode(node.left, teamNumber);
} else {
return searchNode(node.right, teamNumber);
}
}
public double getAverageSearchLength() {
return (double) totalComparisons / totalNodes;
}
public static void main(String[] args) {
BinarySearchTree bst = new BinarySearchTree();
String fileName = "team.txt";
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
String line;
boolean firstLine = true;
while ((line = br.readLine()) != null) {
if (firstLine) {
firstLine = false;
continue;
}
String[] fields = line.split("#");
if (fields.length == 6) {
int teamNumber = Integer.parseInt(fields[0].trim());
String projectName = fields[1].trim();
String school = fields[2].trim();
String eventCategory = fields[3].trim();
String participant = fields[4].trim();
String mentor = fields[5].trim();
bst.insert(teamNumber, projectName, school, eventCategory, participant, mentor);
}
}
}
catch (IOException e) {
e.printStackTrace();
}
// 提示输入参赛队编号并进行查找
Scanner scanner=new Scanner(System.in);
System.out.println("输入参赛队编号进行查找:");
int inputTeamNumber = scanner.nextInt(); ; // 假设要查找的参赛队编号
Team result = bst.search(inputTeamNumber);
if (result != null) {
System.out.println("查找成功!");
System.out.println("参赛作品名称:" + result.getProjectName());
System.out.println("参赛学校:" + result.getSchool());
System.out.println("赛事类别:" + result.getEventCategory());
System.out.println("参赛者:" + result.getParticipant());
System.out.println("指导老师:" + result.getMentor());
System.out.println("平均查找长度ASL:" + bst.getAverageSearchLength());
} else {
System.out.println("查找失败!");
}
}
}
参赛团队查询
能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr == null || arr.length <= 1) {
return;
}
int[] temp = new int[arr.length];
mergeSort(arr, temp, 0, arr.length - 1);
}
private static void mergeSort(int[] arr, int[] temp, int left, int right) {
if (left >= right) {
return;
}
int mid = left + (right - left) / 2;
mergeSort(arr, temp, left, mid); // 对左半部分进行归并排序
mergeSort(arr, temp, mid + 1, right); // 对右半部分进行归并排序
merge(arr, temp, left, mid, right); // 合并两个有序数组
}
private static void merge(int[] arr, int[] temp, int left, int mid, int right) {
// 将数组元素复制到临时数组
for (int i = left; i <= right; i++) {
temp[i] = arr[i];
}
int i = left; // 左半部分的起始索引
int j = mid + 1; // 右半部分的起始索引
int k = left; // 归并后数组的起始索引
while (i <= mid && j <= right) {
if (temp[i] <= temp[j]) {
arr[k] = temp[i];
i++;
} else {
arr[k] = temp[j];
j++;
}
k++;
}
// 处理剩余的元素
while (i <= mid) {
arr[k] = temp[i];
i++;
k++;
}
// 注意:右半部分的元素已经在原数组中,无需再处理
// 归并后的数组已经有序,无需额外操作
}
public static void main(String[] args) {
int[] arr = {5, 2, 9, 1, 6, 3};
mergeSort(arr);
System.out.println("排序结果:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}
使用归并排序,归并排序算法在排序过程中,相同元素的前后顺序并没有改变,所以归并排序是一种稳定排序算法
决赛叫号模拟
为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)
//叫号系统
//赛区分类
void eventCate_separate(vector<Team> team)
{
vector<string> teameventCate;
for (int i = 0; i < team.size(); i++)
{
if (std::find(teameventCate.begin(), teameventCate.end(), team[i].geteventCate()) == teameventCate.end())
{
teameventCate.push_back(team[i].geteventCate());
}
}
for (int i = 0; i < teameventCate.size(); i++)
{
for (int m = 0; m < team.size(); m++)
{
if (i < 3)
{
if (teameventCate[i] ==team[m].geteventCate())
{
a1.push_back(team[m]);
}
}
if (i>=3&&i<=5)
{
if (teameventCate[i] == team[m].geteventCate())
{
a2.push_back(team[m]);
}
}
if (i >= 6 && i <= 8)
{
if (teameventCate[i] == team[m].geteventCate())
{
a3.push_back(team[m]);
}
}
if (i >= 9 && i <= 11)
{
if (teameventCate[i] == team[m].geteventCate())
{
a4.push_back(team[m]);
}
}
if (i >= 12 && i <= 14)
{
if (teameventCate[i] == team[m].geteventCate())
{
a5.push_back(team[m]);
}
}
if (i >= 15 && i <= 18)
{
if (teameventCate[i] == team[m].geteventCate())
{
a6.push_back(team[m]);
}
}
if (i >= 19 && i <= 22)
{
if (teameventCate[i] == team[m].geteventCate())
{
a7.push_back(team[m]);
}
}
if (i >= 23 && i <= 26)
{
if (teameventCate[i] == team[m].geteventCate())
{
a8.push_back(team[m]);
}
}
if (i >= 27 && i < teameventCate.size())
{
if (teameventCate[i] == team[m].geteventCate())
{
a9.push_back(team[m]);
}
}
}
}
}
//获得你想要的赛区
vector<Team> search_zone(int i)
{
if (i == 1)
{
return a1;
}
if (i == 2)
{
return a2;
}
if (i == 3)
{
return a3;
}
if (i == 4)
{
return a4;
}
if (i == 5)
{
return a5;
}
if (i == 6)
{
return a6;
}
if (i == 7)
{
return a7;
}
if (i == 8)
{
return a8;
}
if (i == 9)
{
return a9;
}
}
//进场顺序
void Approach_sequence(vector<Team>& team)
{
for (int i = 0; i < team.size(); i++)
{
cout<<"第"<<i+1<<" 个队伍编号为:" <<team[i].getTeamID() << endl;
}
}
//模拟叫号
void Call_system(vector<Team> team)
{
cout<<"********叫号开始!**********" << endl;
cout <<"第1次" << "叫到的编号为:" << team[0].getTeamID() << endl;
team.pop_back();
for (int i = 1; i < team.size(); i++)
{
string a;
cin >> a;
if (a == "继续")
{
cout<<"第" <<i+1<< "次叫到的编号为:" << team[i].getTeamID() << endl;
team.pop_back();
}
else if(a!="继续")
{
cout<<"比赛还在继续,请继续等待!" << endl;
}
else if (i == team.size())
{
cout<<"比赛已经完成!" << endl;
}
}
}
赛事系统为参赛者提供赛地的校园导游程序。为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供图中任意目标地(建筑物)的问路查询,即查询任意两个目的地(建筑物)之间的一条最短的简单路径。
//导航系统
string join(string s, vector<unsigned> list) { // 拼接向量元素为字符串
if (list.empty()) return "";
string res(to_string(list[0]));
for (auto i = list.begin() + 1; i != list.end(); ++i) {
res += s;
res += to_string(*i);
}
return res;
}
class Floyd {
private:
unsigned n; // 结点数
vector<vector<double>> mat; // 邻接矩阵
vector<vector<unsigned>> pre; // 前驱结点表
void floyd() { // Floyd算法具体实现
for (unsigned k = 0; k < n; ++k) // 依次作为中继结点
for (unsigned i = 0; i < n; ++i)
for (unsigned j = 0; j < n; ++j)
if (mat[i][j] > mat[i][k] + mat[k][j]) { // 以中继更新其他点
mat[i][j] = mat[i][k] + mat[k][j];
pre[i][j] = k;
}
}
public:
Floyd( // 构造:结点数,边集,是否无向
unsigned n,
vector<tuple<unsigned, unsigned, double>> edges,
bool undirected = true)
:n(n), mat(vector<vector<double>>(n, vector<double>(n, DBL_MAX))) {
for (unsigned i = 0; i < n; ++i) { // 生成邻接矩阵和前驱表
mat[i][i] = 0;
pre.push_back(vector<unsigned>(n, i));
}
for (auto edge : edges) {
auto i = get<0>(edge), j = get<1>(edge);
auto w = get<2>(edge);
mat[i][j] = w;
if (undirected) mat[j][i] = w;
}
floyd();
}
tuple<unsigned, string> operator()(unsigned i, unsigned j) { // 重载()获取结点i到结点j的路径
if (i == j) return { 0, to_string(i) };
if (mat[i][j] == DBL_MAX) return { DBL_MAX, "" };
vector<unsigned> p{ i, j };
unsigned k = 0;
while (k < p.size() - 1) {
auto iter = p.begin() + k;
if (pre[*iter][*(iter + 1)] == *iter) ++k;
else p.insert(iter + 1, pre[*iter][*(iter + 1)]);
}
return { mat[i][j], join("->", p) };
}
};
int identifyposition(string a)
{
if (a == "3号组团")
{
return 0;
}
if (a == "西食堂")
{
return 1;
}
if (a == "文体中心")
{
return 2;
}
if (a == "足球场")
{
return 3;
}
if (a == "文理大楼")
{
return 4;
}
if (a == "笃学楼")
{
return 5;
}
if (a == "东食堂")
{
return 6;
}
if (a == "9号组团")
{
return 7;
}
if (a == "图书馆")
{
return 8;
}
if (a == "计算机学院")
{
return 9;
}
else
{
return -1;
}
}
void searchposition(string a,string b)//用于输入搜索并且打印地址
{
vector<tuple<unsigned, unsigned, double>> es{ // 起点, 终点, 权重
{0, 1, 80},
{0, 2, 150},
{1, 2, 100},
{1, 3, 90},
{1, 4, 120},
{2, 3, 50},
{2, 5, 80},
{2, 6, 160},
{3, 4, 75},
{3, 5, 70},
{4, 5, 80},
{4, 9, 80},
{5, 6, 90},
{5, 8, 80},
{5, 9, 100},
{6, 7, 50},
{6, 8, 70},
{7, 8, 80},
{8, 9, 110}, };
Floyd pathf(10, es);
int m = identifyposition(a);
int n= identifyposition(b);
cout << "地图追踪为:: " << endl;
auto tp = pathf(m,n ); // 结点i到结点j的<最短路径值, 途径结点>
cout << a<<"到" <<b<<"距离为: " << get<0>(tp) << ", 通过的地点编号为: " << get<1>(tp) << endl;
}
总结
这次数据结构课程设计是我本科阶段参与的课程设计项目之一,也是整个专业课程中比较重要的课程之一。这个课程设计的主题是 "赛事系统为参赛者提供赛地的校园导游程序",需要我们使用所学的数据结构和算法知识,设计算法和实现代码,为参赛者提供导游和路径查询服务。
这次课程设计让我更加深刻地体会到了数据结构和算法在计算机科学中的核心地位。通过为解决实际问题而设计算法,这项任务不仅考验了我们对数据结构和算法的理解和应用能力,还考验了我们的系统设计能力、代码实现能力、沟通协调能力等方面的技巧。同时,思考如何使算法更优,代码更美,更有效率,也加深了我对计算机科学领域的认识。
首先,整个课程设计中涉及的数据结构非常庞杂,包括但不限于树、图、堆栈、数组、队列、哈希表等许多基本数据结构。学习如何使用这些数据结构是设计算法的关键。例如,在路径查询问题中,以图数据结构为基础实现了Floyd 算法,计算任意两个目标地之间的最短路径。在导览查询问题中,使用哈希表实现了节点 ID 的映射,直观和方便的为用户提供建筑物信息的查询。
这次课程设计加强了我们对算法分析和代码实现的思考。我们不仅学习理论,还实际运用了所学知识,不断调整我们的代码和算法来满足要求,优化我们的程序并使我们的代码更具可读性和可维护性。因此,做完这次课程的设计,我感到自己的软件设计和分析能力,以及代码的设计和实现能力得到了极大提高。
这次课程设计让我深刻体会到了数据结构与算法在计算机科学中的重要性。通过设计算法来解决实际问题,不仅考验了我们对数据结构和算法的理解和应用能力,也锻炼了我们系统设计能力、代码实现能力、沟通协调能力等方面的技能。同时,不断地思考如何让算法更加高效、如何让代码更加优雅,也推动了我对计算机科学领域的理解更加深入。
在这个过程中,还学到了很多与数据结构和算法相关的知识,例如图论、最短路径算法、排序算法以及树的相关知识。这些知识不仅是实现本次课程设计的基础,也是计算机科学领域不可缺少的重要组成部分,在以后的学习和工作中起着至关重要的作用。
当然,在本次数据结构课程设计中,我体会到了算法的重要性,但同时也发现了一些自己的不足之处。以下是我在这个任务中的不足之处:
·缺乏数据结构和算法的实践经验。虽然在课堂上学习了许多数据结构和算法的知识,但是实际应用过程中,由于缺乏经验,可能会对一些问题的解决方法感到迷茫。
·代码实现效率不算高。为了实现算法,我常常会遇到算法复杂度过高的问题。虽然这可以在一定程度上解决问题,但需要更好的优化代码实现。
总之,这次数据结构课程设计让我受益匪浅,不仅让我深入理解了数据结构和算法的应用,也帮助我提高了自己的编程能力,是一次非常有价值的经历。这次数据结构课程设计拓展了我的知识面,加深了我对数据结构与算法在计算机科学中的认识,在实现算法的过程中锤炼了我的逻辑推理能力和代码编写能力。通过模拟实际中的复杂问题,这次课程设计使我有了一个更加完整的计算机科学方面的认识,也为我日后的学习与工作开辟了更加广阔的前景。