数据结构课程设计——项目1:计算机设计大赛赛事统计
一、问题描述和项目要求
1.1 问题描述
参加计算机设计大赛的n个学校编号为 1~n,赛事分成m个项目,项目的编号为1-m.比赛获奖按照得分降序,取前三名,写一个统计程序产生各种成绩单和得分报表。
1.2 基本要求
1)每个比赛项目至少有10支参赛队;每个学校最多有6支队伍参赛; 每支参赛队伍只能参加一个赛事项目;
2)能统计各学校的总分;
3)可以按照学校编号或名称查询,学校的总分、各项目的总分排序输出;
4)可以按学校编号查询学校某个项目的获奖情况;可以按项目编号查询取得前三名的学校;
5)数据存入文件并能随时查询
1.3 设计要求
1)输入数据形式和范围:可以输入学校的名称,赛事项目的名称。
2)输出形式:有中文提示,各学校分数为整数
3)界面要求:交互设计要合理,每个功能可以设立菜单,根据提示,完成相关功能的要求。
4)存储结构:学生自己根据系统功能要求自己设计,但是赛事相关数据要存储在文件中。
二、 问题分析
2.1 程序数据限制
1)假定赛事项目的编号为1-m,3<m<=10,假定学校编号为 1~n,那么由基本要求的第一条应至少满足6n>=10m。
2)先输入各个编号学校所对应的名称,约定学校名称长度不超过20个字符。每个赛事结束时,将其编号、名称输入,并依次输入参赛学校编号和成绩,成绩范围[0,100]。同分数的同一等奖,例如某赛事分数从高到底有98,97,97,96,95…,那么98分的为一等奖,两个97分的为二等奖,96分的为三等奖。。
2.2 程序需实现的功能
- 需实现功能
- 统计各学校的总分
- 能按照学校编号或名称查找并排序,使学校的总分、各项目的总分排序输出;
- 能按照学校编号查询学校某个项目的获奖情况;能按照项目编号查询取得前三名的学校;
- 赛事数据存入文件并能随时查询
三、逻辑设计
3.1 抽象数据类型的定义
学校类的定义
ADT School
Data:
学校名称
学校编号
指向本学校第一个参赛队伍的指针// java里对象名指向一个对象实例的地址
Operation:
School
输入: 学校名称、学校编号
输出: 无
返回: 无
School// 空参数的构造函数
输入: 无
输出: 无
返回: 无
getTotalScore
输入: 无
输出: 无
返回: 学校总分
printAllMatchScore
输入: 无
输出: 输出学校的总分,并将该学校各项目分数降序输出
返回: 无
sAward
输入: 无
输出: 输出指定学校的获奖情况
返回: 无
getFirstTeam
输入: 无
输出: 无
返回: 指向本学校第一个参赛队伍的指针
endADT
赛事类的定义
ADT Match
Data:
赛事名称
赛事编号
指向第一个参加该赛事的队伍的指针
Operation:
Match:
输入: 赛事编号、赛事名称
输出: 无
返回: 无
Match:// 空参的构造函数
输入: 无
输出: 无
返回: 无
getFirstTeam:
输入: 无
输出: 无
返回: 返回指向第一个参加该赛事的队伍
mAward:
输入: 无
输出: 输出指定赛事的获奖情况(学校、分数和奖项)。
返回: 无
endADT
参赛队伍类的定义
ADT Team
Data:
参赛赛事编号
所属学校编号
获得的分数
指向下一个参加同一赛事队伍的指针
指向同一学校的下一个队伍的指针
Operation:
Team
输入: 参赛赛事编号、所属学校编号、获得的分数
输出: 无
返回: 无
Team// 空参的构造函数
输入: 无
输出: 无
返回: 无
getNextTeam
输入: 无
输出: 无
返回: 指向下一个参加同一赛事队伍的指针
getNextSchoolTeam
输入: 无
输出: 无
返回: 指向同一学校的下一个队伍的指针
endADT
3.2 程序主要模块
- 主要模块
- 模块一 主函数模块
- 模块二 用户操作选择模块
- 模块三 依据学校编号或名称查询学校总分、各项目总分模块
- 模块四 依据学校编号查询学校某个项目的获奖情况模块
- 模块五 依据项目编号查询取得前三名的学校模块
3.3 模块调用关系图
四、物理设计
4.1 存储结构
![学校类节点结构](https://i-blog.csdnimg.cn/blog_migrate/071eaf6ea2345039f338c5ede69e01fe.png#pic_center)
![赛事类结点结构](https://i-blog.csdnimg.cn/blog_migrate/c542a73b207a961f922ab7564feb6e77.png#pic_center)
![参赛队伍类结点结构](https://i-blog.csdnimg.cn/blog_migrate/8caaab1444e111ec67bfe8dcffe4bc36.png#pic_center)
- 存储结构说明:
- 横向共有n条链表,每个链表以学校类结点作为头结点,其中所有的学校类头节点又组成了一个线性表,储存在学校类数组中,数组下标0—n-1分别对应着编号为1—n的学校,其中头结点数据域不为空,储存着各学校的信息。头结点指向该学校第一个参赛队伍。
- 纵向共有m条链表,每个链表以赛事结点作为头结点,其中所有头结点又组成了一个线性表,储存在赛事类数组中,数组下标0—m-1分别对应着编号为1—m的赛事,其中头结点数据域不为空,储存着赛事相关信息。头结点指向着第一个参加该赛事的队伍。
- 当某学校有多个队伍参加同一赛事,就会出现如图中黄色圈出来的结点情况,不过需注意的是这两个结点在内存中是同一个,只是该节点即在所属学校的横向链表中,又在所参加赛事的纵向链表中。
- 其中生成链表结构的算法应保证横向链表参赛队伍结点应以赛事编号升序排列,纵向链参赛队伍结点表应以学校编号升序排列。
- 这样便形成了n+m条链表,形成了一个类十字链表的结构。
- 生成链表的核心java代码
static int n;// 学校数
static int m;// 赛事数
static int[] schoolTeamCount;// 存放各学校参赛队伍数
static int[] matchTeamCount;// 存放各比赛参赛队伍数
static School[] schoolList;// 储存学校信息的线性表,同时作为横向链表的头结点
static Match[] matchList;// 赛事线性表,同时作为纵向链表的头结点
static Scanner input = new Scanner(System.in);// 用于输入数据
// 避免输入的多个数据中学校编号相同,记录各个学校编号是否被初始化
static int[] recordSchool;
// 避免输入的多个数据中赛事编号相同,记录各个赛事编号是否被初始化
static int[] recordMatch ;
Team team = new Team(matchNumber, schoolNumber, score);
schoolTeamCount[schoolNumber - 1]++;
matchTeamCount[matchNumber - 1]++;
Team next = schoolList[schoolNumber - 1].firstTeam;
Team p;
// 开始生成横向链表横向链表以赛事编号升序排序
if (next == null || next.matchNumber >= matchNumber) {
schoolList[schoolNumber - 1].firstTeam = team;
team.schoolNext = next;
} else {
do {
// 横向链表以赛事编号升序排序
p = next;
next = next.schoolNext;
if (next == null || next.matchNumber >= matchNumber) {
p.schoolNext = team;
team.schoolNext = next;
break;
}
} while (true);
}
next = matchList[matchNumber - 1].firstTeam;
// 开始生成纵向链表 纵向向链表以赛事编号升序排序
if (next == null || next.schoolNumber >= schoolNumber) {
matchList[matchNumber - 1].firstTeam = team;
team.matchNext = next;
} else {
do {
// 横向链表以赛事编号升序排序
p = next;
next = next.matchNext;
if (next == null || next.schoolNumber >= schoolNumber) {
p.matchNext = team;
team.matchNext = next;
break;
}
} while (true);
}
4.2 算法设计
4.2.1 学校类的成员方法: getTotalScore
- 作用: 得到该学校的总分
- 伪代码:
1. 初始化 count=0,将该学校的所在横向链表的头指针指赋值给指针next
2. count加上next所指向结点的成绩,next向后移一位
3. 当next不为空,重复步骤2
4. 返回count
4.2.2 学校类的成员方法: printAllMatchScore
- 作用: 输出该学校的总分,并将该学校各项目分数降序输出
- 伪代码:
1. 先调用成员方法getTotalScore得到该学校的总分并输出
2. 遍历该学校所在横向链表的所有参赛队伍结点,将参赛队伍的成绩和参加赛事编号装入一个二维数组。
3. 调用排序方法sort对该二维数组按照成绩进行降序排序。
4. 输出排序后的结果
4.3.3 非成员非友元方法:printAllScoolTotalScore
- 作用: 将所有学校的总分排序输出
- 伪代码:
1. 遍历学校结点所在的线性表,调用成员方法getTotalScore得到每个学校的分数,并将每个学校的分数和学校编号装入一个二维数组
2. 调用排序方法sort对该二维数组按照成绩进行降序排序。
3. 输出排序后的结果
4.3.4 赛事类的成员方法: mAward
- 作用: 输出指定赛事的获奖情况(学校、分数和奖项)。
- 伪代码:
1. 遍历指定赛事所在的纵向链表,将所有参加该赛事的队伍所在学校编号和成绩放入一个二维数组
2. 调用排序方法sort对该二维数组按照成绩进行降序排序。
3. 输出排序后的结果
4.3.5 非成员非友元方法: sort
- 作用: 传入参数为二维数组,对该二维数组[][]按照[i][0]降序排序
- 伪代码:快速排序算法,详细过程略
4.3.6 学校类的成员方法:sAward
- 作用: 输出指定学校的获奖情况。
- 伪代码:
foreach(学校所在横向链表中的队伍结点)
foreach(队伍结点所在纵向链表中的队伍结点){
// 多个该学校队伍参加同一赛事,该赛事所在纵向队列只遍历一次
将队伍结点所属学校编号和成绩存入一个二维数组
掉用sort方法对该二维数组按照成绩进行降序排序
如果最高的三个成绩中有队伍属于指定的学校
输出该队伍的获奖获奖情况(赛事、分数和奖项)
}
五、JAVA源码:
import java.io.*;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Match_Management {
/**
* 参赛队伍类
*/
static class Team {
/**
* 赛事编号
*/
int matchNumber;
/**
* 所属学校编号
*/
int schoolNumber;
/**
* 该赛事获得的分数,范围[0,100]
*/
int score;
/**
* 指向下一个参加同一赛事队伍的指针
*/
Team matchNext;
/**
* 指向同一学校的下一个队伍的指针
*/
Team schoolNext;
/**
* 参数为空的构造函数
*/
public Team() {
this.matchNumber = -1;
this.schoolNumber = -1;
this.score = -1;
this.schoolNext = null;
this.matchNext = null;
}
/**
* 构造函数
*/
public Team(int matchNumber, int schoolNumber, int score) {
this.matchNumber = matchNumber;
this.schoolNumber = schoolNumber;
this.score = score;
this.schoolNext = null;
this.matchNext = null;
}
/**
* @return 返回指向同一学校的下一个队伍的指针
*/
public Team getSchoolNext() {
return schoolNext;
}
/**
* @return 返回指向下一个参加同一赛事队伍的指
*/
public Team getMatchNext() {
return matchNext;
}
}
/**
* 学校类
*/
static class School {
/**
* 学校名字
*/
String schoolName;
/**
* 指向本学校第一个参赛队伍的指针
*/
Team firstTeam;
/**
* 学校编号
*/
int schoolNumber;
/**
* 参数为空的构造函数
*/
public School() {
this.schoolName = null;
this.firstTeam = null;
this.schoolNumber = -1;
}
/**
* @param schoolName 学校名字
* @param schoolNumber 学校编号
*/
public School(String schoolName, int schoolNumber) {
this.schoolName = schoolName;
this.firstTeam = null;
this.schoolNumber = schoolNumber;
}
/**
* @return 返回指向本学校第一个参赛队伍的指针
*/
public Team getFirstTeam() {
return firstTeam;
}
/**
* @return 返回本学校所得总分
*/
public int getTotalScore() {
int count = 0;
Team next;// 作为遍历链表的指针
next = firstTeam;
while (next != null) {
count += next.score;
next = next.schoolNext;
}
return count;
}
/**
* 输出学校总分,并使本学校各项目分数降序输出
*/
public void printAllMatchScore() {
if (schoolTeamCount[schoolNumber - 1] == 0) {
System.out.println("该学校参加的所有比赛结果均未公布,敬请等候");
return;
}
int[][] ans = new int[schoolTeamCount[schoolNumber - 1]][2];
Team next;// 作为遍历链表的指针
next = firstTeam;
int i = 0;// 遍历数组
while (next != null) {
// 数据放入数组
ans[i][0] = next.matchNumber;
ans[i++][1] = next.score;
next = next.schoolNext;
}
sort(ans, 0, ans.length - 1);// 降序排序
// 开始输出
System.out.println("学校所有参赛队伍获得的总分:" + getTotalScore() +
"\t\t学校编号:" + schoolNumber + "\t\t学校名:"
+ schoolList[schoolNumber - 1].schoolName);
System.out.printf("%12s", "队伍成绩");
System.out.printf("%12s", "赛事编号");
System.out.printf("%20s", "赛事名称");
System.out.println();
for (i = 0; i < ans.length; i++) {
System.out.printf("%13s", ans[i][1]);
System.out.printf("%16s", ans[i][0]);
String s = matchList[ans[i][0] - 1].matchName;
for (int t = 0; t < 18; t++) {
s = " " + s;
}
System.out.println(s);
}
}
/**
* 输出指定学校的获奖情况
*/
public void sAward() {
if (schoolTeamCount[schoolNumber - 1] == 0) {
System.out.println("该学校参加的所有比赛结果均未公布,敬请等候");
return;
}
int[] record = new int[m];// 记录该学校所有参赛项目编号
Team next = schoolList[schoolNumber - 1].firstTeam;
while (next != null) {
// 遍历该学校所有参赛队伍并记录该学校所有参赛项目编号
record[next.matchNumber - 1] = 1;
next = next.schoolNext;
}
System.out.println("学校编号:" + schoolNumber + "\t学校名称:"
+ schoolList[schoolNumber - 1].schoolName);
int flag = 0;// 记录该学校有无奖项
for (int i = 0; i < m; i++) {
if (record[i] == 1) {
int[][] ans =