BLOG-3
BLOG-3
- 前言
本次blog主要是对PTA题目集7、8以及期末考试的总结及分析,重点是对课程成绩统计程序2、3以及期末考试的总结。
课程成绩统计2和3都是在课程成绩统计1的基础上的延伸,课程成绩统计程序2在第一次的基础上增加了实验课,课程成绩统计程序3在第二次的基础上修改了计算总成绩的方式,将成绩类的继承关系改为组合关系。
这两次的大作业和期末考试题目主要考察了Java中类的结构构造,继承和多态以及HashMap数组的排序方式。
相比于之前的菜单计价系列题目来说,这次的大作业题目要相对简单一点点,部分的类结构和用法和之前类似。
- 程序设计分析
第七次PTA题目集
一、题目:
7-2 课程成绩统计程序-2
课程成绩统计程序-2在第一次的基础上增加了实验课,以下加粗字体显示为本次新增的内容。
某高校课程从性质上分为:必修课、选修课、实验课,从考核方式上分为:考试、考察、实验。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。
考察的总成绩直接等于期末成绩
实验的总成绩等于课程每次实验成绩的平均分
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。实验课的成绩必须为实验。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式(可选,如果性质是必修课,考核方式可以没有)三个数据项。
课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
课程性质输入项:必修、选修、实验
考核方式输入选项:考试、考察、实验
考试/考查课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
考试/考查课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
实验课程成绩信息包括:学号、姓名、课程名称、实验次数、每次成绩
实验次数至少4次,不超过9次
实验课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+实验次数+英文空格+第一次实验成绩+...+英文空格+最后一次实验成绩
以上信息的相关约束:
1)平时成绩和期末成绩的权重默认为0.3、0.7
2)成绩是整数,不包含小数部分,成绩的取值范围是【0,100】
3)学号由8位数字组成
4)姓名不超过10个字符
5)课程名称不超过10个字符
6)不特别输入班级信息,班级号是学号的前6位。
2、输出:
输出包含三个部分,包括学生所有课程总成绩的平均分、单门课程成绩平均分、单门课程总成绩平均分、班级所有课程总成绩平均分。
为避免误差,平均分的计算方法为累加所有符合条件的单个成绩,最后除以总数。
1)学生课程总成绩平均分按学号由低到高排序输出
格式:学号+英文空格+姓名+英文空格+总成绩平均分
如果某个学生没有任何成绩信息,输出:学号+英文空格+姓名+英文空格+"did not take any exams"
2)单门课程成绩平均分分为三个分值:平时成绩平均分(可选)、期末考试平均分、总成绩平均分,按课程名称的字符顺序输出
考试/考察课程成绩格式:课程名称+英文空格+平时成绩平均分+英文空格+期末考试平均分+英文空格+总成绩平均分
实验课成绩格式:课程名称+英文空格+总成绩平均分
如果某门课程没有任何成绩信息,输出:课程名称+英文空格+"has no grades yet"
3)班级所有课程总成绩平均分按班级由低到高排序输出
格式:班级号+英文空格+总成绩平均分
如果某个班级没有任何成绩信息,输出:班级名称+英文空格+ "has no grades yet"
异常情况:
1)如果解析某个成绩信息时,课程名称不在已输入的课程列表中,输出:学号+英文空格+姓名+英文空格+":"+课程名称+英文空格+"does not exist"
2)如果解析某个成绩信息时,输入的成绩数量和课程的考核方式不匹配,输出:学号+英文空格+姓名+英文空格+": access mode mismatch"
以上两种情况如果同时出现,按第一种情况输出结果。
3)如果解析某个课程信息时,输入的课程性质和课程的考核方式不匹配,输出:课程名称+" : course type & access mode mismatch"
4)格式错误以及其他信息异常如成绩超出范围等,均按格式错误处理,输出"wrong format"
5)若出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
信息约束:
1)成绩平均分只取整数部分,小数部分丢弃
参考类图(与第一次相同,其余内容自行补充):
输入样例1:
在这里给出一组输入。例如:
java 实验 实验
20201103 张三 java 4 70 80 90
end
输出样例1:
在这里给出相应的输出。例如:
20201103 张三 : access mode mismatch
20201103 张三 did not take any exams
java has no grades yet
202011 has no grades yet
输入样例2:
在这里给出一组输入。例如:
java 实验 实验
20201103 张三 java 3 70 80 90
end
输出样例2:
在这里给出相应的输出。例如:
wrong format
java has no grades yet
输入样例3:
在这里给出一组输入。例如:
java 必修 实验
20201103 张三 java 3 70 80 90 100
end
输出样例3:
在这里给出相应的输出。例如:
java : course type & access mode mismatch
wrong format
输入样例4:
在这里给出一组输入。例如:
java 必修 实验
20201103 张三 java 4 70 80 90 105
end
输出样例4:
在这里给出相应的输出。例如:
java : course type & access mode mismatch
wrong format
输入样例5:
在这里给出一组输入。例如:
java 选修 考察
C语言 选修 考察
java实验 实验 实验
编译原理 必修 考试
20201101 王五 C语言 76
20201216 李四 C语言 78
20201307 张少军 编译原理 82 84
20201103 张三 java实验 4 70 80 90 100
20201118 郑觉先 java 80
20201328 刘和宇 java 77
20201220 朱重九 java实验 4 60 60 80 80
20201132 王萍 C语言 40
20201302 李梦涵 C语言 68
20201325 崔瑾 编译原理 80 84
20201213 黄红 java 82
20201209 赵仙芝 java 76
end
输出样例5:
在这里给出相应的输出。例如:
20201101 王五 76
20201103 张三 85
20201118 郑觉先 80
20201132 王萍 40
20201209 赵仙芝 76
20201213 黄红 82
20201216 李四 78
20201220 朱重九 70
20201302 李梦涵 68
20201307 张少军 83
20201325 崔瑾 82
20201328 刘和宇 77
C语言 65 65
java 78 78
java实验 77
编译原理 81 84 82
202011 70
202012 76
202013 77
二、设计思路:
类设计如下:
Main类:包含主方法,用于读取输入并调用systemin类的方法。
score抽象类:包含总分、平时成绩和期末成绩属性及对应的getter方法。其中总分属性为抽象方法,具体实现在其子类中。
Testscore类:继承自score类,实现了总分计算方法,其中总分由平时成绩和期末成绩按照一定比例计算得出。
Otherscore类:继承自score类,实现了总分计算方法,总分即为期末成绩。
Course类:表示课程,包含课程名称、课程类型和考核方式属性,以及对应的getter方法。
Student类:表示学生,包含学号和姓名属性,以及对应的getter方法。
SelectCourse类:表示选课情况,包含课程、学生和成绩属性,以及对应的getter和setter方法。
systemin类:包含一系列方法,用于处理输入数据并进行相应的操作,如添加课程、学生、选课信息等,还提供了获取平均成绩的方法。
Imatch类:提供了一些静态方法,用于判断输入数据的格式是否正确。
类与类之间的关系如下:
- Testscore类和Otherscore类继承了父类score类。
- SelectCourse类关联了Course类、Student类和score抽象类,表示学生选课情况,并存储了对应的成绩信息。
- systemin类包含了ArrayList集合对象,分别存储了选课信息、课程信息和学生信息。通过调用这些集合对象的方法,实现了添加、查找和计算平均成绩等操作。
- Main类通过创建systemin类的对象,并调用其方法来处理输入数据。
- Imatch类提供了一些静态方法,用于判断输入数据的格式是否正确。
三、代码展示:
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String test = input.nextLine();
systemin key=new systemin();
while (!test.equals("end")) {
key.systemin(test);
test = input.nextLine();
}
key.Sort();
key.getnum();
key.getcourse();
key.getclass();
}
}
abstract class score{
double Totalscore;
public int getTotalscore() {
return (int) Totalscore;
}
public int getUsualscore() {
return 0;
}
public int getFinalscore() {
return 0;
}
}
class Testscore extends score{
int Usualscore;
int Finalscore;
public int getTotalscore(){
return (int)(0.3*this.getUsualscore()+0.7*this.getFinalscore());
}
public int getUsualscore() {
return Usualscore;
}
public void setUsualscore(int usualscore) {
Usualscore = usualscore;
}
public int getFinalscore() {
return Finalscore;
}
public void setFinalscore(int finalscore) {
Finalscore = finalscore;
}
}
class Otherscore extends score{
int Finalscore;
public int getTotalscore(){
return Finalscore;
}
public int getFinalscore() {
return Finalscore;
}
public void setFinalscore(int finalscore) {
Finalscore = finalscore;
}
}
class Course{
String name;
String kind;
String method;
public Course(String name, String kind, String method) {
this.name = name;
this.kind = kind;
this.method = method;
}
public String getName() {
return name;
}
public String getMethod() {
return method;
}
}
class Student{
String num;
String name;
public Student(String num, String name) {
this.num = num;
this.name = name;
}
public String getNum() {
return num;
}
public String getName() {
return name;
}
}
class SelectCourse{
Course course;
Student student;
score score;
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public score getscore() {
return score;
}
public void setgd(score score) {
this.score = score;
}
}
class systemin{
private final ArrayList<SelectCourse> selectCourses = new ArrayList<>();
private final ArrayList<Course> courses = new ArrayList<>();
private final ArrayList<Student> students = new ArrayList<>();
private final ArrayList<String> Class = new ArrayList<>();
private final HashMap<String,String> cm=new HashMap();
public void systemin(String input){
String []Student=input.split(" ");
if(Imatch.minput(input)==1){
cm.put(Student[0],Student[2]);
if(checkC(Student[0])!=null)return;
else {
if(Student[1].equals("必修")&&(!Student[2].equals("考试"))){
System.out.println(Student[0]+" : course type & access mode mismatch");
}
else if(Student[1].equals("选修")&&!(Student[2].equals("考试")||Student[2].equals("考察"))){
System.out.println(Student[0]+" : course type & access mode mismatch");
}
else if(Student[1].equals("实验")&&!(Student[2].equals("实验"))){
System.out.println(Student[0]+" : course type & access mode mismatch");
}
else courses.add(new Course(Student[0],Student[1],Student[2]));
}
}
else if(Imatch.minput(input)==2){
Course findcourse=checkC(Student[2]);
if(Student.length>5&&(Integer.parseInt(Student[3])<4||Integer.parseInt(Student[3])>9)) {
System.out.println("wrong format");
return;
}
Student newStudent = new Student(Student[0],Student[1]);
if(!checkStudent(newStudent.getNum()))students.add(newStudent);
if(!checkClass(Student[0].substring(0,6))){
Class.add(Student[0].substring(0,6));
}
if(cs(Student[0],Student[2]))return;
if(findcourse==null){
System.out.println(Student[2]+" does not exist");
return;
}
else if(findcourse.getMethod().equals("考试")&&Student.length!=5){
System.out.println(Student[0]+' '+Student[1]+" : access mode mismatch");
}
else if(findcourse.getMethod().equals("考察")&&Student.length!=4){
System.out.println(Student[0]+' '+Student[1]+" : access mode mismatch");
}
else if(findcourse.getMethod().equals("实验")&&(Student.length-4!=Integer.parseInt(Student[3]))){
System.out.println(Student[0]+' '+Student[1]+" : access mode mismatch");
}
else{
SelectCourse newSelectCourse=new SelectCourse();
newSelectCourse.setCourse(findcourse);
score score=null;
if(findcourse.getMethod().equals("考试")){
Testscore testscore=new Testscore();
testscore.setUsualscore(Integer.parseInt(Student[3]));
testscore.setFinalscore(Integer.parseInt(Student[4]));
score=testscore;
}
else if(findcourse.getMethod().equals("实验")){
Otherscore otherscore=new Otherscore();
double sumScore=0;
for (int i=4;i<Student.length;i++)sumScore+=Integer.parseInt(Student[i]);
otherscore.setFinalscore((int)(sumScore/Integer.parseInt(Student[3])));
score=otherscore;
}
else {
Otherscore otherscore=new Otherscore();
otherscore.setFinalscore(Integer.parseInt(Student[3]));
score=otherscore;
}
newSelectCourse.setgd(score);
newSelectCourse.setStudent(newStudent);
selectCourses.add(newSelectCourse);
}
}
else System.out.println("wrong format");
}
private Course checkC(String courseName){
for (Course course:courses){
if(course.getName().equals(courseName))return course;
}
return null;
}
private Boolean checkStudent(String num){
for (Student student:students){
if(student.getNum().equals(num))return true;
}
return false;
}
private Boolean checkClass(String classnum){
for (String cname:Class){
if(cname.equals(classnum))return true;
}
return false;
}
private Boolean cs(String stunum,String cname){
for (SelectCourse selectCourse:selectCourses){
if(selectCourse.getStudent().getNum().equals(stunum)&&selectCourse.getCourse().getName().equals(cname))return true;
}
return false;
}
public void getnum(){
for (Student student:students){
double sum=0;
int temp=0;
for (SelectCourse selectCourse:selectCourses){
if (selectCourse.getStudent().getNum().equals(student.getNum()))
{
sum+=selectCourse.getscore().getTotalscore();
temp++;
}
}
if(temp==0) System.out.println(student.getNum()+' '+student.getName()+' '+"did not take any exams");
else System.out.println(student.getNum()+' '+student.getName()+' '+(int)(sum/temp));
}
}
public void getcourse(){
for (Course course:courses){
double sumUsualScore=0;
double sumFinalScore=0;
double sumTotalScore=0;
int count=0;
for(SelectCourse selectCourse:selectCourses){
if(selectCourse.getCourse().getName().equals(course.getName())){
count++;
sumTotalScore+=selectCourse.getscore().getTotalscore();
sumFinalScore+=selectCourse.getscore().getFinalscore();
if(selectCourse.getCourse().getMethod().equals("考试")){
sumUsualScore+=selectCourse.getscore().getUsualscore();
}
}
}
if (count==0) System.out.println(course.getName()+' '+"has no grades yet");
else if(course.getMethod().equals("考试"))System.out.println(course.getName()+' '+(int)(sumUsualScore/count)+' '+(int)(sumFinalScore/count)+' '+(int)(sumTotalScore/count));
else if(course.getMethod().equals("考察"))System.out.println(course.getName()+' '+(int)(sumFinalScore/count)+' '+(int)(sumTotalScore/count));
else if(course.getMethod().equals("实验"))System.out.println(course.getName()+' '+(int)(sumFinalScore/count));
}
}
public void getclass(){
for (String classnum:Class){
double sum=0;
int temp=0;
for (SelectCourse selectCourse:selectCourses){
if(selectCourse.getStudent().getNum().substring(0,6).equals(classnum)){
sum+=selectCourse.getscore().getTotalscore();
temp++;
}
}
if(temp==0) System.out.println(classnum+' '+"has no grades yet");
else System.out.println(classnum+' '+(int)(sum/temp));
}
}
public void Sort(){
students.sort(Comparator.comparing(Student::getNum));
courses.sort((x,y)->{
Collator instance = Collator.getInstance(Locale.CHINA);
return instance.compare(x.getName(), y.getName());
} );
Collections.sort(Class);
}
}
class Imatch {
static String stuNumMatching = "[0-9]{8}";
static String stuNameMatching = "\\S{1,10}";
static String scoreMatching = "(\\d|[1-9]\\d|100)";
static String courseNameMatching = "\\S{1,10}";
static String courseTypeMatching = "(选修|必修|实验)";
static String checkcourseTypeMatching = "(考试|考察|实验)";
static String courseInput = courseNameMatching + " " + courseTypeMatching + " " + checkcourseTypeMatching;
static String scoreInput = stuNumMatching + " " + stuNameMatching + " " + courseNameMatching + " " +
scoreMatching + "(\\s"+scoreMatching+")*";
public static int minput(String s) {
if (matchingCourse(s)) {
return 1;
}
if (matchingScore(s)) {
return 2;
}
return 0;
}
private static boolean matchingCourse(String s) {
return s.matches(courseInput);
}
private static boolean matchingScore(String s) {
return s.matches(scoreInput);
}
}
- 类图
第八次PTA题目集
- 题目:
7-2 课程成绩统计程序-3
课程成绩统计程序-3在第二次的基础上修改了计算总成绩的方式,
要求:修改类结构,将成绩类的继承关系改为组合关系,成绩信息由课程成绩类和分项成绩类组成,课程成绩类组合分项成绩类,分项成绩类由成绩分值和权重两个属性构成。
完成课程成绩统计程序-2、3两次程序后,比较继承和组合关系的区别。思考一下哪一种关系运用上更灵活,更能够适应变更。
题目最后的参考类图未做修改,大家根据要求自行调整,以下内容加粗字体显示的内容为本次新增的内容。
某高校课程从性质上分为:必修课、选修课、实验课,从考核方式上分为:考试、考察、实验。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。
考察的总成绩直接等于期末成绩
实验的总成绩等于课程每次实验成绩乘以权重后累加而得。
课程权重值在录入课程信息时输入。(注意:所有分项成绩的权重之和应当等于1)
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。实验课的成绩必须为实验。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式、分项成绩数量、每个分项成绩的权重。
考试课信息格式:课程名称+英文空格+课程性质+英文空格+考核方式+英文空格+平时成绩的权重+英文空格+期末成绩的权重
考察课信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
实验课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式+英文空格+分项成绩数量n+英文空格+分项成绩1的权重+英文空格+。。。+英文空格+分项成绩n的权重
实验次数至少4次,不超过9次
课程性质输入项:必修、选修、实验
考核方式输入选项:考试、考察、实验
考试/考查课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
考试/考查课程成绩信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
实验课程成绩信息包括:学号、姓名、课程名称、每次成绩{在系列-2的基础上去掉了(实验次数),实验次数要和实验课程信息中输入的分项成绩数量保持一致}
实验课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+第一次实验成绩+...+英文空格+最后一次实验成绩
以上信息的相关约束:
1)成绩是整数,不包含小数部分,成绩的取值范围是【0,100】
2)学号由8位数字组成
3)姓名不超过10个字符
4)课程名称不超过10个字符
5)不特别输入班级信息,班级号是学号的前6位。
2、输出:
输出包含三个部分,包括学生所有课程总成绩的平均分、单门课程总成绩平均分、班级所有课程总成绩平均分。
为避免四舍五入误差,
计算单个成绩时,分项成绩乘以权重后要保留小数位,计算总成绩时,累加所有分项成绩的权重分以后,再去掉小数位。
学生总成绩/整个班/课程平均分的计算方法为累加所有符合条件的单个成绩,最后除以总数。
1)学生课程总成绩平均分按学号由低到高排序输出
格式:学号+英文空格+姓名+英文空格+总成绩平均分
如果某个学生没有任何成绩信息,输出:学号+英文空格+姓名+英文空格+"did not take any exams"
2)单门课程成绩按课程名称的字符顺序输出
课程成绩输出格式:课程名称+英文空格+总成绩平均分
如果某门课程没有任何成绩信息,输出:课程名称+英文空格+"has no grades yet"
3)班级所有课程总成绩平均分按班级由低到高排序输出
格式:班级号+英文空格+总成绩平均分
如果某个班级没有任何成绩信息,输出:班级名称+英文空格+ "has no grades yet"
异常情况:
1)如果解析某个成绩信息时,课程名称不在已输入的课程列表中,输出:学号+英文空格+姓名+英文空格+":"+课程名称+英文空格+"does not exist"
2)如果解析某个成绩信息时,输入的成绩数量和课程的考核方式不匹配,输出:学号+英文空格+姓名+英文空格+": access mode mismatch"
以上两种情况如果同时出现,按第一种情况输出结果。
3)如果解析某个课程信息时,输入的课程性质和课程的考核方式不匹配,输出:课程名称+" : course type & access mode mismatch"
4)格式错误以及其他信息异常如成绩超出范围等,均按格式错误处理,输出"wrong format"
5)若出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
6)如果解析实验课程信息时,输入的分项成绩数量值和分项成绩权重的个数不匹配,输出:课程名称+" : number of scores does not match"
7)如果解析考试课、实验课时,分项成绩权重值的总和不等于1,输出:课程名称+" : weight value error"
信息约束:
1)成绩平均分只取整数部分,小数部分丢弃
参考类图(与第一次相同,其余内容自行补充):
输入样例1:
在这里给出一组输入。例如:
java 实验 实验 4 0.2 0.3 0.2 0.3
end
输出样例1:
在这里给出相应的输出。例如:
java has no grades yet
输入样例2:
在这里给出一组输入。例如:
java 实验 实验 4 0.2 0.3 0.2
end
输出样例2:
在这里给出相应的输出。例如:
java : number of scores does not match
输入样例3:
在这里给出一组输入。例如:
java 实验 实验 4 0.2 0.3 0.2 0.1
end
输出样例3:
在这里给出相应的输出。例如:
java : weight value error
输入样例4:
在这里给出一组输入。例如:
java 实验 实验 4 0.2 0.3 0.2 0.3
20201116 张三 java 70 80 90 100
end
输出样例4:
在这里给出相应的输出。例如:
20201116 张三 86
java 86
202011 86
输入样例5:
在这里给出一组输入。例如:
java 实验 实验 4 0.2 0.3 0.2 0.3
20201116 张三 java 70 80 90 100 80
end
输出样例5:
在这里给出相应的输出。例如:
20201116 张三 : access mode mismatch
20201116 张三 did not take any exams
java has no grades yet
202011 has no grades yet
- 设计思路
类设计如下:
Choose类:表示学生选择的课程和成绩信息,其中包含Course、Student和Score对象。表示了学生选课和成绩的关联关系。
Course类:表示课程信息,包含课程名称、性质、考试方式等属性。与Choose类关联,表示了课程和学生选课之间的关系。
Student类:表示学生信息,包含学号和姓名。与Choose类关联,表示了学生和选课成绩之间的关系。
myClass类:表示班级信息,包含班级ID和学生列表。与Student类关联,表示了班级和学生之间的关系。
ParseInput类:包含对输入数据的解析和处理方法,包含了对Course、Student和Choose的管理和操作。
Score类及其子类:表示学生成绩信息,包含了不同类型的成绩计算方式,与Choose类关联,表示了学生成绩的具体信息。
Main类:包含了程序的入口点main方法,用于接收用户输入的数据,并调用ParseInput类进行处理。
- 代码展示
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.text.Collator;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
class Choose {
Course course;
Student student;
Score score;
public Course getCourse() {
return course;
}
public Student getStudent() {
return student;
}
public Choose(Course course, Student student, Score score) {
this.course = course;
this.student = student;
this.score = score;
}
}
class InputMatching {
static String stuNumMatching = "[0-9]{8}"; // 8个数字
static String stuNameMatching = "\\S{1,10}"; // 1到10个非空格字符
static String scoreMatching = "([1-9]?[0-9]|100)"; // 0到100的成绩
static String courseNameMatching = "\\S{1,10}"; // 1到10个非空格字符
static String courseTypeMatching = "(选修|必修|实验)"; // 课程类型:选修、必修或实验
static String checkcourseTypeMatching = "(考试|考察|实验)"; // 考试方式:考试、考察或实验
static String experimentNumber = "[4-9]"; // 实验号码:4到9
// 课程信息模式
static String courseInput = courseNameMatching + " " + courseTypeMatching + " " + checkcourseTypeMatching;
static String courseInput0 = courseNameMatching + " 必修 考试 \\d+\\.\\d+ \\d+\\.\\d+";
static String courseInput1 = courseNameMatching + " 实验 实验 " + experimentNumber + " \\d+\\.\\d+( \\d+\\.\\d+){2,9}";
// 成绩信息模式
static String scoreInput = stuNumMatching + " " + stuNameMatching + " " + courseNameMatching + " " + scoreMatching;
static String scoreInput1 = stuNumMatching + " " + stuNameMatching + " " + courseNameMatching + " " + scoreMatching + "( " + scoreMatching + "){1,9}";
public static int matchingInput(String s) {
if (matchingCourse(s)) {
return 1;
}
if (matchingScore(s)) {
return 2;
}
return 0;
}
private static boolean matchingCourse(String s) {
return s.matches(courseInput) || s.matches(courseInput0) || s.matches(courseInput1);
}
private static boolean matchingScore(String s) {
return s.matches(scoreInput) || s.matches(scoreInput1);
}
}
class Course implements Comparable<Course> {
private String csName;
private String csCharacter;
private String csExamine;
private int number;
private double[] weight;
public Course(String csName, String csCharacter, String csExamine, int number, double[] weight) {
this.csName = csName;
this.csCharacter = csCharacter;
this.csExamine = csExamine;
this.number = number;
this.weight = weight;
}
public Course(String csName, String csCharacter, String csExamine, double[] weight) {
this(csName, csCharacter, csExamine, 0, weight);
}
public Course(String csName, String csCharacter, String csExamine) {
this(csName, csCharacter, csExamine, 0, null);
}
public String getCsName() {
return csName;
}
public String getCsCharacter() {
return csCharacter;
}
public String getCsExamine() {
return csExamine;
}
public int getNumber() {
return number;
}
public double[] getWeight() {
return weight;
}
@Override
public int compareTo(Course o) {
return csName.compareTo(o.csName);
}
}
class myClass implements Comparable<myClass>{
private String ID;
ArrayList<Student> listStudent=new ArrayList<>();
void addStudent(Student stu){
listStudent.add(stu);
}
public myClass(String ID) {
this.ID = ID;
}
public String getID() {
return ID;
}
@Override
public int compareTo(myClass myclass){
return ID.compareTo(myclass.getID());
}
}
class ParseInput{
ArrayList<Course> courseArrayList = new ArrayList<>();
ArrayList<Student> studentArrayList = new ArrayList<>();
ArrayList<Choose> chooseArrayList = new ArrayList<>();
ArrayList<myClass> classArrayList = new ArrayList<>();
public void parseInput(String nextLine) {
String[] arraylist = nextLine.split(" ");
int inputType = InputMatching.matchingInput(nextLine);
if (inputType == 1) {
inputCourse(arraylist);
} else if (inputType == 2) {
inputScore(arraylist);
} else {
System.out.println("wrong format");
}
}
Course getCourse(String courseName){
for (Course course : courseArrayList) {
if (course.getCsName().equals(courseName))
return course;
}
return null;
}
myClass getclass(String classId){
for (myClass myClass : classArrayList) {
if (myClass.getID().equals(classId))
return myClass;
}
return null;
}
Student getStudent(String stuId){
for (Student student : studentArrayList) {
if (student.getStNumber().equals(stuId))
return student;
}
return null;
}
private void inputScore(String[] a) {
myClass myClass = getclass(a[0].substring(0, 6));
if (myClass == null) {
myClass = new myClass(a[0].substring(0, 6));
classArrayList.add(myClass);
}
Student student = getStudent(a[0]);
if (student == null) {
student = new Student(a[0], a[1]);
studentArrayList.add(student);
myClass.addStudent(student);
}
Course course = getCourse(a[2]);
if (course == null) {
System.out.println(a[2] + " does not exist");
return;
}
if (!checkGrade(a, course)) {
return;
}
double[] weight = course.getWeight();
int length = a.length - 3;
Score score = null;
switch (length) {
case 1:
score = new kcScore(Integer.parseInt(a[3]));
break;
case 2:
score = new ksScore(Integer.parseInt(a[3]), Integer.parseInt(a[4]), weight);
break;
default:
int[] flag = new int[length];
for (int i = 0; i < flag.length; i++) {
flag[i] = Integer.parseInt(a[i + 3]);
}
score = new syScore(flag, 0, weight);
break;
}
if (existChooseCourse(student, course)) {
return;
}
Choose chooseCourse = new Choose(course, student, score);
chooseArrayList.add(chooseCourse);
}
public void inputCourse(String[] a) {
if (getCourse(a[0]) != null) {
return;
}
Course course;
double[] weight;
if (a[2].equals("实验") && a.length > 7) {
weight = sypart(a);
course = new Course(a[0], a[1], a[2], Integer.parseInt(a[3]), weight);
} else if (a[2].equals("考试") && a.length == 5) {
weight = kspart(a);
course = new Course(a[0], a[1], a[2], weight);
} else {
course = new Course(a[0], a[1], a[2]);
}
if (!checkCourse(a, course)) {
return;
}
if (a[2].equals("考察") && a.length == 3) {
course = new Course(a[0], a[1], a[2]);
} else if (a[2].equals("实验") && a.length >= 8) {
weight = sypart(a);
course = new Course(a[0], a[1], a[2], Integer.parseInt(a[3]), weight);
} else if (a[2].equals("考试") && a.length == 5) {
weight = kspart(a);
course = new Course(a[0], a[1], a[2], 0, weight);
} else {
return;
}
Course searchedCourse = searchCourse(course);
if (searchedCourse != null) {
courseArrayList.add(searchedCourse);
}
}
double[] kspart(String[] b){
double [] t = new double[2];
for (int i = 0; i < t.length; i++) {
t[i]=Float.parseFloat(b[i+3]);
}
return t;
}
double [] sypart(String[] b){
double [] a = new double[Integer.parseInt(b[3])];
for (int i = 0; i < a.length; i++) {
a[i]= Float.parseFloat(b[i+4]);
}
return a;
}
boolean checkCourse(String[] items, Course course) {
Map<String, List<String>> validTypesByExamine = new HashMap<>();
validTypesByExamine.put("考试", Arrays.asList("必修", "选修"));
validTypesByExamine.put("考察", Arrays.asList("选修"));
validTypesByExamine.put("实验", Arrays.asList("实验"));
if (!validTypesByExamine.containsKey(course.getCsExamine())) {
System.out.println(course.getCsName() + " : unknown examine type");
return false;
}
if (!validTypesByExamine.get(course.getCsExamine()).contains(course.getCsCharacter())) {
System.out.println(course.getCsName() + " : course type & access mode mismatch");
return false;
}
switch (course.getCsExamine()) {
case "考试":
if (items.length != 5 || !isValidWeight(items, 3, 4)) {
return false;
}
break;
case "考察":
if (items.length != 3) {
System.out.println(course.getCsName() + " : number of scores does not match");
return false;
}
break;
case "实验":
int expectedNum = Integer.parseInt(items[3]);
if (items.length - 4 != expectedNum || !isValidWeight(items, 4, items.length)) {
return false;
}
break;
}
return true;
}
private boolean isValidWeight(String[] items, int start, int end) {
double sum = 0;
StringBuilder errorMsg = new StringBuilder();
for (int i = start; i < end; i++) {
double weight = Double.parseDouble(items[i]);
if (weight < 0 || weight > 1) {
errorMsg.append(items[0]).append(" : weight value error\n");
}
sum += weight;
}
if (Math.abs(sum - 1.0) > 0.000001) {
errorMsg.append(items[0]).append(" : weight value error\n");
}
if (errorMsg.length() > 0) {
System.out.println(errorMsg.toString());
return false;
}
return true;
}
boolean existChooseCourse(Student stu,Course course){
for (Choose choose : chooseArrayList) {
if (choose.getCourse().getCsName().equals(course.getCsName())) {
if (choose.getStudent().getStNumber().equals(stu.getStNumber()))
return true;
}
}
return false;
}
Course searchCourse(Course course){
for (Choose choose : chooseArrayList) {
if (choose.getCourse().getCsName().equals(course.getCsName())) {
return null;
}
}
return course;
}
private boolean checkGrade(String[] items, Course course) {
String courseType = course.getCsExamine();
int expectedLength = -1;
switch (courseType) {
case "考试":
expectedLength = 5;
break;
case "考察":
expectedLength = 4;
break;
case "实验":
expectedLength = 3 + course.getNumber();
break;
default:
System.out.println("Unknown examine type for course: " + course.getCsName());
return false;
}
if (items.length != expectedLength) {
System.out.println(items[0] + " " + items[1] + " : access mode mismatch");
return false;
}
return true;
}
public int getAvgTotalScore(ArrayList<Choose> listChooseCourse) {
int sum = 0;
for (Choose cs : listChooseCourse) {
sum += cs.score.getTotalScore();
}
return Math.round((float) sum / listChooseCourse.size());
}
public int getScore(ArrayList<Choose> courseSelects) {
float sum = 0;
for (Choose cs : courseSelects) {
sum += cs.score.getExperimentScore();
}
return Math.round(sum / courseSelects.size());
}
public ArrayList<Choose> getStudentSelects(String stNumber) {
ArrayList<Choose> stus = new ArrayList<>();
for (Choose choose : chooseArrayList) {
if (choose.student.getStNumber().equals(stNumber)) {
stus.add(choose);
}
}
if(stus.size()!=0)
return stus;
else return null;
}
public ArrayList<Choose> getCourseSelects(String courseName){
ArrayList<Choose> courses = new ArrayList<>();
for (Choose choose : chooseArrayList) {
if (choose.course.getCsName().equals(courseName)) {
courses.add(choose);
}
}
if(courses.size()!=0)
return courses;
else return null;
}
public ArrayList<Choose> getClassSelects(String classID){
ArrayList<Choose> classes = new ArrayList<>();
for (Choose choose : chooseArrayList) {
if (choose.student.getStNumber().substring(0, 6).equals(classID)) {
classes.add(choose);
}
}
if(classes.size()!=0)
return classes;
else return null;
}
public void showStudents() {
Collections.sort(studentArrayList);
for (Student student : studentArrayList) {
ArrayList<Choose> stuCourseSelects = getStudentSelects(student.getStNumber());
//从总选课表Choose中获取该生的选课记录集合
if (stuCourseSelects != null) {
System.out.println(student.getStNumber() + " " + student.getStName() + " " + getAvgTotalScore(stuCourseSelects));
} else {
System.out.println(student.getStNumber() + " " + student.getStName() + " " + "did not take any exams");
}
}
}
public void showCourses() {
Collections.sort(courseArrayList);
for (Course course : courseArrayList) {
ArrayList<Choose> courseSelects = getCourseSelects(course.getCsName());
if (courseSelects != null && !courseSelects.isEmpty()) {
String examineType = course.getCsExamine();
String avgScore = "";
if (examineType.equals("考试") || examineType.equals("考察")) {
avgScore = String.valueOf(getAvgTotalScore(courseSelects));
} else if (examineType.equals("实验")) {
avgScore = String.valueOf(getScore(courseSelects));
}
System.out.println(course.getCsName() + " " + avgScore);
} else {
System.out.println(course.getCsName() + " has no grades yet");
}
}
}
public void showClasses() {
Collections.sort(classArrayList);
for (myClass myClass : classArrayList) {
ArrayList<Choose> stuClassSelects = getClassSelects(myClass.getID());
if (stuClassSelects != null) {
System.out.println(myClass.getID() + " " + getAvgTotalScore(stuClassSelects));
} else {
System.out.println(myClass.getID() + " " + "has no grades yet");
}
}
}
}
class Student implements Comparable<Student>{
private String stuNumber;
private String stuName;
public Student(String stuNumber, String stuName) {
this.stuName=stuName;
this.stuNumber=stuNumber;
}
public String getStNumber() {
return stuNumber;
}
public String getStName() {
return stuName;
}
@Override
public int compareTo(Student student){
return getStNumber().compareTo(student.getStNumber());
}
}
abstract class Score{
public int Score2;//期末
public int totalScore;
public float getTotalScore() {
return totalScore;
}
public float getExperimentScore() {
return totalScore;
}
Score(int finalScore){this.Score2=finalScore;}
}
class ksScore extends Score{//考试
private int Score1;//平时
ksScore(int usualScore, int finalScore,double [] b){
super(finalScore);
this.Score1=usualScore;
this.totalScore=(int)(Score1*b[0]+finalScore*b[1]);
}
}
class kcScore extends Score{//考察
kcScore(int finalScore){
super(finalScore);
this.totalScore=finalScore;
}
}
class syScore extends Score{//实验
syScore(int [] a,int finalScore,double [] b){
super(finalScore);
double total=0;
for (int i = 0; i <a.length; i++) {
for (int j = 0; j < b.length; j++) {
total+=(a[i]*b[i]);
}
}
this.totalScore= (int)total/a.length;
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String inputString = input.nextLine();
ParseInput handle=new ParseInput();
while (!inputString.equals("end")) {
handle.parseInput(inputString);//解析用户输入的每一行数据
inputString = input.nextLine();
}
handle.showStudents();
handle.showCourses();
handle.showClasses();
}
}
- 类图
期末考试题目3:
一、题目
7-3 魔方排序问题
在魔方问题的基础上,重构类设计,实现列表内魔方的排序功能(按照魔方的体积进行排序)。
提示:题目中RubikCube类要实现Comparable接口。
其中,Main类源码如下(可直接拷贝使用):
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
String color;
int layer;
double side;
RubikCube cube;
ArrayList<RubikCube> list = new ArrayList<>();
int choice = input.nextInt();
while(choice != 0) {
switch(choice) {
case 1://SquareCube
color = input.next();
layer = input.nextInt();
side = input.nextDouble();
cube = new SquareCube(color, layer,new Cube(side));
list.add(cube);
break;
case 2://RegularPyramidCube
color = input.next();
layer = input.nextInt();
side = input.nextDouble();
cube = new RegularPyramidCube(color, layer,new RegularPyramid(side));
list.add(cube);
break;
}
choice = input.nextInt();
}
list.sort(Comparator.naturalOrder());//正向排序
for(int i = 0; i < list.size(); i++) {
System.out.print(list.get(i).getColor() + " " +
String.format("%.2f", list.get(i).getArea()) + " " +
String.format("%.2f", list.get(i).getVolume()) );
System.out.println("");
}
}
}
输入格式:
输入魔方类型(1:正方体魔方;2:正三棱锥魔方;0:结束输入)
魔方颜色、魔方阶数、魔方单元正方体、正三棱锥边长
..循环..
输出格式:
按魔方体积升序输出列表中各魔方的信息(实型数均保留两位小数),输出样式参见输出样例。
输入样例:
在这里给出一组输入。例如:
1 blue 3 4.5
2 red 4 2.1
1 yellow 5 2.3
2 black 4 9.42
1 white 4 5.4423
0
输出样例:
在这里给出相应的输出。例如:
red 122.21 69.85
yellow 793.50 1520.88
blue 1093.50 2460.38
black 2459.14 6304.73
white 2843.39 10316.38
- 设计思路
类设计如下:
RubikCube类:表示一个魔方对象,包含颜色、层数和实体等属性,以及获取表面积和体积的方法。实现了Comparable接口,用于比较不同魔方对象的体积大小。
Cube类:表示一个立方体实体,包含边长属性和获取表面积、体积的方法。实现了Solid接口,表示具有表面积和体积计算能力。
SquareCube类:表示一个以正方形为表面的魔方对象,继承自RubikCube类,包含一个立方体实体作为其“单位块”,重写了获取表面积和体积的方法。
RegularPyramid类:表示一个正四面体实体,包含侧长属性和获取表面积、体积的方法。实现了Solid接口,表示具有表面积和体积计算能力。
RegularPyramidCube类:表示一个以正四面体为表面的魔方对象,继承自RubikCube类,包含一个正四面体实体作为其“单位块”,重写了获取表面积和体积的方法。
Main类:程序入口,通过用户输入创建魔方对象并添加到ArrayList中,然后对ArrayList中的对象进行排序输出。
Solid接口:定义了获取表面积和体积的抽象方法,被Cube和RegularPyramid类实现。
三、代码展示
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Comparator;
class RubikCube implements Comparable<RubikCube> {
private String color;
protected int layer;
private Solid solid;
public RubikCube(String color, int layer, Solid solid) {
this.color = color;
this.layer = layer;
this.solid = solid;
}
public String getColor() {
return color;
}
public double getArea() {
return solid.getSurfaceArea() * layer * layer;
}
public double getVolume() {
return solid.getVolume() * layer * layer * layer;
}
@Override
public int compareTo(RubikCube other) {
if (this.getVolume() < other.getVolume()) {
return -1;
} else if (this.getVolume() > other.getVolume()) {
return 1;
}
return 0;
}
}
class Cube implements Solid {
protected double side;
public Cube(double side) {
this.side = side;
}
@Override
public double getSurfaceArea() {
return 6 * side * side;
}
@Override
public double getVolume() {
return Math.pow(side, 3);
}
}
class SquareCube extends RubikCube {
private Cube unitCube;
public SquareCube(String color, int layer, Cube unitCube) {
super(color, layer, unitCube);
this.unitCube = unitCube;
}
@Override
public double getArea() {
return layer * layer * unitCube.getSurfaceArea();
}
@Override
public double getVolume() {
return layer * layer * layer * unitCube.getVolume();
}
}
class RegularPyramid implements Solid {
protected double side;
public RegularPyramid(double side) {
this.side = side;
}
@Override
public double getSurfaceArea() {
return side * side * Math.sqrt(3);
}
@Override
public double getVolume() {
return ((Math.sqrt(2)) * side * side * side) / 12;
}
}
class RegularPyramidCube extends RubikCube {
private RegularPyramid unitPyramid;
public RegularPyramidCube(String color, int layer, RegularPyramid unitPyramid) {
super(color, layer, unitPyramid);
this.unitPyramid = unitPyramid;
}
@Override
public double getArea() {
return layer * layer * unitPyramid.getSurfaceArea();
}
@Override
public double getVolume() {
return layer * layer * layer * unitPyramid.getVolume();
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String color;
int layer;
double side;
RubikCube cube;
ArrayList<RubikCube> list = new ArrayList<>();
int choice = input.nextInt();
while (choice != 0) {
switch (choice) {
case 1: // SquareCube
color = input.next();
layer = input.nextInt();
side = input.nextDouble();
cube = new SquareCube(color, layer, new Cube(side));
list.add(cube);
break;
case 2: // RegularPyramidCube
color = input.next();
layer = input.nextInt();
side = input.nextDouble();
cube = new RegularPyramidCube(color, layer, new RegularPyramid(side));
list.add(cube);
break;
}
choice = input.nextInt();
}
list.sort(Comparator.naturalOrder()); // 正向排序
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i).getColor() + " ");
System.out.printf("%.2f ", list.get(i).getArea());
System.out.printf("%.2f\n", list.get(i).getVolume());
}
}
}
interface Solid {
double getSurfaceArea();
double getVolume();
}
四、类图
- 踩坑心得
1.类名、方法名、变量名等命名规范:在 Java 中,类名、方法名和变量名都要符合一定的命名规范。类名首字母要大写,方法名和变量名的首字母要小写,多个单词之间用驼峰命名法连接,例如 RubikCube、getSurfaceArea()、unitPyramid 等。
2.继承和实现接口:Java 中使用 extends 实现继承,使用 implements 实现接口。需要注意的是,一个类可以继承一个父类,但是可以实现多个接口。
3.访问控制修饰符:Java 中有四种访问控制修饰符,分别是 public、protected、default 和 private。public 表示公共的,任何地方都可以访问;protected 表示受保护的,只有本类、子类和同一包中的其他类可以访问;default 表示默认的,只有同一包中的其他类可以访问;private 表示私有的,只有本类可以访问。
4.排序:Java 中可以使用 Collections.sort() 方法对集合进行排序,也可以使用 List.sort() 方法进行排序。需要注意的是,需要实现 Comparable 接口并重写 compareTo() 方法才能使用这些方法进行排序。
5.ArrayList的并发访问:
在Table类中的records属性是一个ArrayList,在多线程环境下可能存在并发访问的问题。如果涉及到多线程操作,需要考虑使用线程安全的集合类或者对ArrayList进行适当的同步处理。
6.中文排序问题:如果需要对中文进行排序,需要使用Collator类来比较字符串,以避免中文排序错误的问题。
7.计算平均分时,需要注意小数的精度问题,可以将得分取整后再计算平均分。
8.如果输入中有重复的学生选课信息,需要进行去重处理,以避免重复计算成绩。可以使用HashMap等数据结构快速判断是否已经存在该选课信息。
- 代码改进建议
1.课程成绩统计类:
- 类名和方法名应该使用驼峰命名法,例如将systemin改为SystemIn、getnum改为getNum等,以符合Java的命名规范。
- 在score抽象类中,将Totalscore属性的类型改为int,因为它的取值范围是整数。
- 在Testscore和Otherscore类中,可以将Usualscore和Finalscore属性的访问修饰符改为private,并提供公有的setter和getter方法,以封装属性的访问。
- 在Course类中,可以添加公有的setter和getter方法来获取和设置课程的名称、类型和考试方式。在Student类中,可以添加公有的setter和getter方法来获取和设置学生的学号和姓名。
- 在SelectCourse类中,可以将属性的访问修饰符改为私有,并提供公有的setter和getter方法,以封装属性的访问。
- 在SystemIn类中,可以将selectCourses、courses、students和Class这些集合类的访问修饰符改为私有,并提供公有的方法来操作这些集合类,以控制对数据的访问和修改。
- 在SystemIn类中,可以将一些重复的代码抽取为私有方法,提高代码的重用性和可读性。
- 在Imatch类中,可以将正则表达式的匹配模式定义为常量,以提高代码的可维护性和可读性。
2.期末:
- 在SquareCube和RegularPyramidCube类中,可以在构造方法中进行参数合法性检查,确保输入的边长或层数是合理的(大于0),并在不合理时抛出异常或给出错误提示。
- 在RegularPyramid类中,可以将getSurfaceArea()方法中的Math.sqrt(3)提取为一个常量,以提高代码的可读性。可以使用Math.pow(side, 3)代替side * side * side,提高代码的简洁性。
- 在Main类中,可以添加异常处理机制,例如捕获InputMismatchException异常,以防止用户输入非法的数据类型。
- 总结
在编写上述代码的实验过程中,我学到了许多关于类设计和面向对象编程的知识。下面是我的实验总结:
1.良好的类设计原则:
在开始编写代码之前,先进行合理的类设计是非常重要的。良好的类设计应该遵循单一职责原则、开放封闭原则、依赖倒置原则等基本原则。
2.合理的类和方法命名:
类和方法的命名应该清晰、准确地表达其功能和用途,以提高代码的可读性和可维护性。
3.合理使用数据结构和数据类型:
在选择数据结构和数据类型时,要根据实际需求进行合理选择。例如,在菜单类中使用ArrayList来管理菜品列表,在订单记录类中使用HashMap来存储订单信息。
4.异常处理:
在编写代码时,要考虑可能出现的异常情况,并进行合理的异常处理。这样可以增加程序的健壮性和可靠性。
5.代码重用:
在设计类和方法时,要尽量避免重复代码的出现。可以利用继承、接口、组合等技术来实现代码的重用,提高代码的可维护性和可扩展性。
6.代码风格和格式:
在编写代码时,要注意良好的代码风格和格式。使用适当的缩进、注释和命名规范,可以提高代码的可读性和可理解性。
7.测试和调试:
在编写代码后,进行测试和调试是非常重要的。通过单元测试和集成测试,可以验证代码的正确性,并发现潜在的问题和bug。
总的来说,这次实验对我的面向对象编程能力和代码设计能力有了很大的提升。我学会了如何合理地设计和组织类,如何处理异常情况,以及如何进行代码的测试和调试。通过这次实验,我对面向对象编程的思想和原则有了更深入的理解,这对我的编程能力将产生长远的影响。