课程设计内容
中国大学生计算机设计大赛省级赛事管理系统
中国大学生计算机设计大赛是我国高校面向本科生的计算机应用设计大赛,大赛旨在激发学生学习计算机知识和技能的兴趣与潜能,提高学生运用信息技术解决实际问题的综合能力。通过大赛这种计算机教学实践形式,可展示师生的教与学成果,最终以赛促学,以赛促教,以赛促创。该赛事在历届学生中影响力较大,参与者众多。
请了解该赛事组织及管理方式,利用数据结构课程所学的相关知识,为中国大学生计算机设计大赛江苏省组委会设计一个省级赛事管理系统。以2021年省赛数据为例,通过对数据的处理和分析,设计合理的数据结构对赛事相关的数据进行存储及处理。赛事相关数据存储在文本文件和excel文件中,文件中不同的数据项之间均使用#分隔,图1中给出了文件team.txt中参赛信息的对应数据示例。
图1. 参赛队基本信息
【任务描述】
设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:
- 赛事信息管理:从team.txt中读取参赛队伍的基本信息,设计合适的数据结构存储,能实现对参赛队伍的增加、修改和浏览。为参赛队伍分配一个分数为60~100之间的初赛成绩,并能实现参赛队伍的成绩查询(实现基于二叉排序树的查找)。设计合适的输入输出,根据提示输入参赛队编号,查询队伍的初赛成绩,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和初赛成绩信息)。另外,输出全部参赛队的平均查找长度ASL。
(2)决赛现场模拟:首先进行决赛分组,生成决赛秩序册,供参赛队查询。根据赛事类别将参赛队伍分配到17个决赛室(编号为1~17)。秩序册中每个决赛室的进场顺序为初赛成绩降序排列。(排序算法从选择排序、插入排序、希尔排序、归并排序、堆排序中选择一种,并为选择该算法的原因做出说明)然后,模拟决赛秩序。比赛现场会设置大型候赛区,场地中有大屏以时间线动态展示各决赛室中正在决赛的队伍,侯赛的队伍及比赛结束的队伍信息。请编写程序模拟候赛区大屏上动态展示各参赛队候场、比赛中、比赛结束的状态。
(3)决赛地图导览:为参赛者提供决赛主办地的各种路径导航的查询服务,以我校长山校区提供比赛场地为例,为参赛者提供不少于12个目标地的导航。为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供图中任意目标地(建筑物)的问路查询。
实验方案
关于重要类的定义:
文件管理类,负责从文件中读取参赛队信息,以及将参赛队信息存储到文件中。
Team:参赛队类,包含队伍编号、参赛作品名称、参赛学校、赛事类别、参赛者、指导老师、初赛成绩等属性。
SearchTree:二叉排序树类,包含查找、插入、删除等相关操作,能够输出全部参赛队的平均查找长度。
HashTabel:参赛队管理类,负责对参赛队进行增加、删除、修改等操作。
查询系统类,负责按学校或赛事类别查询参赛团队。
决赛叫号系统类,负责模拟决赛叫号过程。
Guide:校园导游类,负责提供校园导航服务。(采用图类)
分析:
一、参赛队伍信息管理
采用散列表查找的方法,将需要查找的关键码通过散列函数运算出对应的值作为其关键码的地址,并按此地址存储该记录。查找是可以直接定位该数据的位置。散列技术优势在于查找速度相比于比较查找技术的查找速度快,且能灵活增加删除元素。利用成员函数实现插入、删除、查找等动态查找的基本操作。
后定义Team结构体,使用函数从文件中获取每个队伍的信息,使散列表能够获取队伍的信息,用户输入的信息(参赛队编号、作品名称、学校、赛事类别、参赛者、指导老师)进行信息增加、删除和修改。
struct Team
{
string id; //参赛编号
string name; //作品名称
string school; //参赛学校
string competitiontype; //赛事类别
string participants; //参赛者
string teacher; //指导老师
};
struct Node
{
Node *next;
};
const int MaxSize =500;
class HashTable
{
public:
HashTable( ); //构造函数,初始化开散列表
~HashTable( ); //析构函数,释放同义词子表结点
void Insert(struct Team); //插入
void Delete(struct Team); //删除
void Amend(&struct Team); //修改
Node* Search(struct Team); //查找
void Print( );
private:
int H(int k); //散列函数
Node * ht[MaxSize]; //开散列表
};
基于二叉排序树查找队伍信息
二叉排序树的构建(插入)
根据二叉树的定义,向二叉排序树中插入一个结点所含的信息首先需要查找该结点的位置,然后在执行插入操作。新结点作为叶子插入到二叉排序树中,无论是插在左子树还是右子树,若有某个结点值与被插入结点值相同则规定将其插在右子树中。插入过程是递归的。左子树上的值均小于根结点的值;右子树上的值均大于根结点的值。
构造树:通过不断调用二叉排序的插入算法而进行。
编号查询成绩,并输出相关信息
在search函数中,先判断root是否为空。若root是空树,则查找失败返回空,否者执行以下操作:
(1)若目标值等于root->data,则查找成功并返回当前结点值;
(2)若目标值小于root->data,则递归调用search函数,在root的左子树上进行查找;
(3)若目标值大于root->data,则递归调用search函数,在root的右子树上进行查找;
最后返回找到的节点,不为空的话输出查找成功信息和查找长度。查找成功平均查找长度 : ASL=每层层数乘以每层结点个数之和除以二叉排序树的结点总个数。
最终函数中的返回该结点的对象信息。
struct BiNode
{
int data; //分数 层树
BiNode *lchild, *rchild;
};
class BiSortTree
{
public:
BiSortTree(int a[ ], int n); //建立查找集合a[n]的二叉排序树
~ BiSortTree( ){ Release(root); } //析构函数,同二叉链表的析构函数
void InOrder( ){InOrder(root);} //中序遍历二叉树
BiNode *InsertBST(int x) {return InsertBST(root, x);} //插入记录x
void DeleteBST(BiNode *p, BiNode *f ); //删除f的左孩子p
BiNode *SearchBST(int k) {return SearchBST(root, k);}//查找值为k的结点
float AvgSearchLenth(BiNode *root,int level);//计算查找成功平均查找长度
void Find(struct Team); //队伍信息
private:
void Release(BiNode *bt);
BiNode*InsertBST(BiNode *bt , int x);
BiNode *SearchBST(BiNode *bt, int k);
void InOrder(BiNode*bt); //中序遍历函数调用
BiNode *root; //二叉排序树的根指针
};
二、决赛现场模拟
分配决赛室,将队伍按照赛事类别分配到17个决赛室。需要一个类或者结构体来存储初队伍的参赛类型信息,并将其分派到不同的决赛室,这决定了每个类别的参赛顺序。在每个实验室中按照每个队伍的初赛成绩降序进行排列。应初赛成绩信息属于大规模数据,考虑采用堆排序或归并排序,堆排序具有较低的空间复杂度,但是并不是稳定的排序算法。但每个决赛室中相同初赛成绩的队伍相对位置改变后并不会产生严重后果,且堆排序实现难度较低,故采用堆排序。
void Sort::HeapSort( )
{
int i, temp;
for (i = ceil(length/2) - 1; i >= 0; i--) //从最后一个分支结点至根结点
Sift(i, length-1) ;
for (i = 1; i < length; i++)
{
temp = data[0]; data[0] = data[length-i]; data[length-i] = temp;
Sift(0, length-i-1); //重建堆
}
}
模拟比赛大屏展示比赛状态
比赛现场会设置大型候赛区,场地中有大屏以时间线动态展示各决赛室中正在决赛的队伍,侯赛的队伍及比赛结束的队伍信息。选择队列作为数据结构。比赛结束的队伍对于出队元素,正在决赛中的队伍对于在队列中的元素,候赛的队伍对于入队的元素。每个元素处于出队、入队、在队列中时,都会返回队伍的相关信息。
struct Node
{
int data;
Node* next;
};
class LinkQueue
{
public:
LinkQueue(void);
~LinkQueue(void);
void Enqueuqe(int a);//入队
void Getdata();//取正在队列中的元素
int Dequeue();//出队
private:
Node* rear;
};
#include "stdafx.h"
#include "LinkQueue.h"
LinkQueue::LinkQueue() {
rear = new Node;
rear->next = rear;
rear->data = NULL;
}
LinkQueue::~LinkQueue(void)
{
}
void LinkQueue::Enqueuqe(int x)
{
if (rear->data == NULL)
{
rear->data = x;
}
else
{
Node* p;
p = new Node;
p->data = x;
p->next = rear->next;
rear->next = p;
rear = p;
}
return x;
}
int LinkQueue::Dequeue()
{
int x = rear->next->data;
Node* s = rear->next;
rear->next = s->next;
delete s;
return x;
}
void LinkQueue:: Getdata()
{
while(real!=nullptr)
{
real++;
return data[real];
}
}
三、决赛地图导览
为参赛者提供不少于12个目标地的导航。为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供图中任意目标地(建筑物)的问路查询。需输出目的地(建筑物)名称、代号、简介等信息;最短路径的输出需包含途经地及最短路径值;并分析主要算法的时间复杂度。
采用邻接表作为学校地图的存储结构。因为邻接表的时间性能比领接矩阵高。在最短路径的算法选择中采用Dijkstra算法(单源最短路径)。
struct EdgeNode //定义边表结点
{
int adjvex; //邻接点域
EdgeNode *next;
};
struct VertexNode //定义顶点表结点
{
int vertex;
EdgeNode *firstEdge;
};
const int MaxSize = 100; //图的最多顶点数
int visited[MaxSize] = {0};
class Guide
{
public:
Guide(DataType a[ ], int n, int e); //构造函数,建立n个顶点e条边的图
~Guide( ); //析构函数,释放邻接表各边表结点的存储空间
void Search(int v); //查询
private:
VertexNode adjlist[MaxSize]; //存放顶点表的数组
int vertexNum, edgeNum; //图的顶点数和边数
};
最短路径:
算法:Dijkstra算法 输入:有向网图 G=(V,E),源点 v 输出:从 v 到其他所有顶点的最短路径 1. 初始化:集合S = {v};dist(v, vi) = w<v, vi>, (i=1...n); 2. 重复下述操作直到 S == V 2.1 dist(v, vk) = min{dist(v, vj), (j=1..n)}; 2.2 S = S + {vk}; 2.3 dist(v, vj)=min{dist(v, vj), dist(v, vk) + w<vk, vj>};