(1)前言
在这6-8次PTA作业中,我们没有继续进行点菜的题目练习,而是从新开始了一个关于成绩管理系统的相关练习,而在这三次练习中,我觉得第一次是最具有难度的,因为后两次的成绩系统都是在前一次的基础上进行改进,所以在第一次作业中构建好一个合理的类是尤为重要的,因为一个合理的类可以大大减少后期修改代码的工作量,而在几次作业中,给我带来的最大的收获就是让代码更有逻辑性,将代码分块化,使其更容易被读懂并且更容易经营维护。
(2)设计与分析
1.第六次PTA:
这是首次的成绩系统,在这次,我们要把所需要的类构建完成,以便后面进行修改
类图如下:
在此次的作业中,基本上完全按照题目中所提示的类图进行构建,但是在输入数据的处理上,没有选择以往的传统的处理方式,而是选择运用的正则表达式进行处理:
class InputMatching { static String stuNumMatching = "[0-9]{8}";//8个0-9的数字 static String stuNameMatching = "\\S{1,10}";//1到10个非空格(TAB)字符 static String scoreMatching = "([1-9]?[0-9]|100)"; static String courseNameMatching = "\\S{1,10}";//1到10个非空格(TAB)字符 static String courseTypeMatching = "(选修|必修)"; static String checkCourseTypeMatching = "(考试|考察)"; //courseInput用于定义课程信息模式(正则表达式) static String courseInput = courseNameMatching + " " + courseTypeMatching + " " + checkCourseTypeMatching; //scoreInput用于定义成绩信息模式(正则表达式) static String scoreInput1 = stuNumMatching + " " + stuNameMatching + " " + courseNameMatching + " " + scoreMatching + " "+scoreMatching; static String scoreInput2 = stuNumMatching + " " + stuNameMatching + " " + courseNameMatching + " " + scoreMatching ; 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); } private static boolean matchingScore(String s) { return s.matches(scoreInput1)||s.matches(scoreInput2); } }
这段代码是一个输入匹配类(InputMatching),用于判断输入字符串是否符合特定的模式。主要包含了以下几个静态变量和方法:
stuNumMatching
:表示学号的匹配模式,要求为8个0-9的数字。stuNameMatching
:表示学生姓名的匹配模式,要求为1到10个非空格(TAB)字符。scoreMatching
:表示成绩的匹配模式,要求为1到100的整数。courseNameMatching
:表示课程名称的匹配模式,要求为1到10个非空格(TAB)字符。courseTypeMatching
:表示课程类型的匹配模式,要求为"选修"或"必修"。checkCourseTypeMatching
:表示考核方式的匹配模式,要求为"考试"或"考察"。courseInput
:用于定义课程信息的模式,通过将课程名称、课程类型和考核方式的匹配模式以空格连接而成。scoreInput1
:用于定义包含两个成绩的成绩信息的模式,包括学号、学生姓名、课程名称和两个成绩的匹配模式。scoreInput2
:用于定义只包含一个成绩的成绩信息的模式,包括学号、学生姓名、课程名称和一个成绩的匹配模式。matchingInput(String s)
:对输入字符串进行匹配,判断其属于课程信息还是成绩信息。如果匹配课程信息模式,则返回1;如果匹配成绩信息模式,则返回2;如果不匹配任何模式,则返回0。matchingCourse(String s)
:判断输入字符串是否匹配课程信息模式。matchingScore(String s)
:判断输入字符串是否匹配成绩信息模式。
总的来说,这段代码通过正则表达式来定义不同类型的输入模式,并提供了方法来判断输入字符串是否匹配这些模式。通过调用matchingInput
方法,可以判断输入属于课程信息还是成绩信息,并返回相应的结果。
这种新学的方式极大程度上的是输入数据的处理变得简便,大大的减少了代码量。
而根据我所说,代码具有良好的分装性,比如在我的main函数里:
public static void main(String[] args) { Scanner input=new Scanner(System.in); chooseclass chooseclass=new chooseclass(); String line=input.nextLine(); while(!line.equals("end")) { chooseclass.processdata(line); line=input.nextLine(); } chooseclass.showstudent(); chooseclass.showcourse(); chooseclass.showclass(); }
只有这短短的几行,剩下的方法都具体实现在类里面了,很好的体现了代码的封装性。
2.第七次PTA作业:
这是成绩管理系统的第二次作业,与上次不同的是:
实验课程成绩信息包括:学号、姓名、课程名称、实验次数、每次成绩
实验次数至少4次,不超过9次
实验课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+实验次数+英文空格+第一次实验成绩+...+英文空格+最后一次实验成绩
而在上次的作业中,有两个测试点一直是过不去的,因为手里找不到测试数据,所以也不知道具体错在哪里,所以我觉得重新来过,用一种新的方式去重新写这次的代码:
此次实验类图:
从类图中应该也能看出来,这次大部分的类中都只有变量,类似于一个变量储存的作用,而在choosScore中储存了绝大部分的方法
choosScore方法:
class chooseScore { HashMap<String, Class> classes = new HashMap<>(); HashMap<String, Student> students = new HashMap<>(); HashMap<String, Course> scorses = new HashMap<>(); HashMap<String, String> stuinform = new HashMap<>(); void start() { Scanner input = new Scanner(System.in); String s0; String[] s; String number;//学生学号 String studentname;//学生名字 int kind;//0选修 1必修 2实验 while (true) { s0 = input.nextLine(); InputMatching inputMatching=new InputMatching(s0); s = s0.split(" "); if (s[0].equalsIgnoreCase("end")) break; kind=inputMatching.matchingInput(); if ((s.length == 4 && number(s[3]) && s[0].length() == 8) || (s.length == 5 && number(s[3]) && number(s[4])) && s[0].length() == 8)//学生信息 { if (stuinform.get(s[0]) != null && stuinform.get(s[0]).equalsIgnoreCase(s[2])) continue; number = s[0]; studentname = s[1]; Student student; AScore aScore = new AScore(); BScore bScore = new BScore(); Course course; Class c; c = classes.get(s[0].substring(0, 6)); if (c == null) c = new Class(); student = students.get(s[0]); if (student == null) student = new Student(); student.name = studentname; student.number = number; course = scorses.get(s[2]); if (course == null) { student.i--; System.out.println(s[2] + " does not exist"); } else { if (course.kind == 1) {//有平时成绩的 if (s.length == 4) { c.number = s[0].substring(0, 6); students.put(s[0], student); classes.put(c.number, c); System.out.println(number + " " + studentname + " : access mode mismatch"); continue; } aScore.pscore = Integer.parseInt(s[3]); aScore.qscore = Integer.parseInt(s[4]); student.score += aScore.score(); course.pscore += Integer.parseInt(s[3]); course.qscore += Integer.parseInt(s[4]); course.score += aScore.score(); } if (course.kind == 0) { if (s.length == 5) { c.number = s[0].substring(0, 6); students.put(s[0], student); classes.put(c.number, c); System.out.println(number + " " + studentname + " : access mode mismatch"); continue; } bScore.score = Integer.parseInt(s[3]); student.score += Integer.parseInt(s[3]); course.qscore += Integer.parseInt(s[3]); course.score += bScore.score; } } c.number = s[0].substring(0, 6); student.i++; students.put(s[0], student); if (course != null) { course.i++; scorses.put(course.name, course); } classes.put(c.number, c); stuinform.put(s[0], s[2]); continue; } if (Pattern.matches(inputMatching.pattern, s0) || Pattern.matches(inputMatching.pattern1, s0))//课程信息 { if (s.length == 2 && s[1].equalsIgnoreCase("选修")) { System.out.println("wrong format"); continue; } Course course; course = scorses.get(s[0]); if (course == null) course = new Course(); else continue; if (s.length == 3 && s[1].equalsIgnoreCase("必修") && (s[2].equalsIgnoreCase("考察") || s[2].equalsIgnoreCase("实验"))) { System.out.println(s[0]+" : course type & access mode mismatch"); continue; } if (s[1].equalsIgnoreCase("选修") && s[2].equalsIgnoreCase("实验")) { System.out.println(s[0]+" : course type & access mode mismatch"); continue; } course.kind = kind; course.name = s[0]; scorses.put(s[0], course); continue; } if (Pattern.matches(inputMatching.pattern2, s0) && Integer.parseInt(s[3]) > 3 && Integer.parseInt(s[3]) <= 9)//实验课课程信息输入 { int sign = 0; for(int i=5;i<=s.length;i++) { if(!number(s[i-1])){System.out.println("wrong format");sign++;} } if ((stuinform.get(s[0]) != null && stuinform.get(s[0]).equalsIgnoreCase(s[2])) || sign != 0) continue; number = s[0]; studentname = s[1]; Student student; Course course; Class c; c = classes.get(s[0].substring(0, 6)); if (c == null) c = new Class(); student = students.get(s[0]); if (student == null) student = new Student(); student.name = studentname; student.number = number; course = scorses.get(s[2]); if (course == null) { student.i--; System.out.println(s[2] + " does not exist"); } else { int sum = 0, i = 5, j = 0; for (; i <= s.length; i++) { sum += Integer.parseInt(s[i - 1]); j++; } if (j != Integer.parseInt(s[3])) { System.out.println(number + " " + studentname + " : access mode mismatch");students.put(s[0], student); classes.put(s[0].substring(0, 6), c); continue; } sum = sum / Integer.parseInt(s[3]); course.score += sum; student.score += sum; } c.number = s[0].substring(0, 6); student.i++; students.put(s[0], student); if (course != null) { course.i++; scorses.put(course.name, course); } classes.put(c.number, c); stuinform.put(s[0], s[2]); continue; } System.out.println("wrong format"); } } boolean number(String str) { Pattern pattern = Pattern.compile("[0-9]*"); Matcher isNum = pattern.matcher(str); if (!isNum.matches()) { return false; } if (Integer.parseInt(str) < 0 || Integer.parseInt(str) > 100) return false; return true; } void putclass(){ Set<String> set1 = classes.keySet(); Object[] arr1 = set1.toArray(); Arrays.sort(arr1); for (Object key : arr1) { Class c1; c1 = classes.get(key); if (c1.i != 0) System.out.println(key + " " + c1.totalscore / c1.i); else System.out.println(key + " has no grades yet"); } } void putstudent(){ Set<String> set =students.keySet(); Object[] arr = set.toArray(); Arrays.sort(arr); for (Object key : arr) { Student student =students.get(key); Class c =classes.get(key.toString().substring(0, 6)); if (student.i != 0) { System.out.println(student.number + " " + student.name + " " + student.score / student.i); c.totalscore += student.score / student.i; c.i++; } else System.out.println(student.number + " " + student.name + " did not take any exams"); } } void putcourse(){ List<String> keyList = new ArrayList<>(scorses.keySet()); keyList.sort((o1, o2) -> { return Collator.getInstance(Locale.CHINA).compare(o1, o2); }); for (String key : keyList) { Course course = scorses.get(key); if (course.i == 0) { System.out.println(course.name + " has no grades yet"); continue; } if (course.kind == 1) System.out.println(course.name + " " + course.pscore / course.i + " " + course.qscore / course.i + " " + course.score / course.i); if (course.kind == 0) System.out.println(course.name + " " + course.qscore / course.i + " " + course.score / course.i); if (course.kind == 2) System.out.println(course.name + " " + course.score / course.i); } } }
其他的类都类似于一种储存变量的方法,在choosScore中分别定义的他们的对象,然后引用他们,在这次作业中的效果不错,得到了满分。
(3).PTA第八次作业
根据题目要求,我们需要修改课程成绩统计程序,将原来的继承关系改为组合关系。具体来说,我们需要创建两个类:课程成绩类和分项成绩类。
课程成绩类包含以下属性:
- 课程名称
- 课程性质
- 考核方式
- 分项成绩列表(即分项成绩类的对象列表)
分项成绩类包含以下属性:
- 成绩分值
- 权重
在计算总成绩时,根据考核方式的不同,采取不同的计算方法:
- 对于考试课,总成绩 = 平时成绩 * 平时成绩权重 + 期末成绩 * 期末成绩权重
- 对于考察课,总成绩 = 期末成绩
- 对于实验课,总成绩 = 所有实验成绩 * 对应权重的累加和
接下来我们需要处理输入和输出。
输入部分:
- 首先,我们需要读入课程信息。根据输入的格式,解析出课程名称、课程性质、考核方式以及分项成绩的数量和权重。
- 然后,根据输入的考核方式,判断是否符合课程性质和考核方式的要求。
- 接着,我们读入学生的成绩信息。根据输入的格式,解析出学号、姓名、课程名称以及对应的成绩(平时成绩和期末成绩,或者实验成绩)。
- 对于实验课,还需要检查实验成绩数量和分项成绩权重的个数是否匹配。
输出部分:
- 首先,计算每个学生的总成绩并按照学号由低到高排序输出。如果某个学生没有任何成绩信息,输出相应提示。
- 接着,计算每门课程的总成绩并按照课程名称的字符顺序输出。如果某门课程没有任何成绩信息,输出相应提示。
- 最后,计算每个班级的总成绩平均分并按照班级号由低到高排序输出。如果某个班级没有任何成绩信息,输出相应提示。
在处理输入和输出时,我们需要注意异常情况的处理,包括格式错误、课程名称不存在、成绩数量和考核方式不匹配、课程性质和考核方式不匹配等。
综上所述,我们需要进行适当的修改来实现题目要求,并使用组合关系来构建课程成绩类和分项成绩类之间的关系。在具体实现过程中,需要注意对输入的解析和对异常情况的处理。
此次作业类图:
在此次作业中,主要也就是多了这个:
if(8==s[0].length()&&s[1].length()<=10&&s.length<=13)//实验课课程信息输入 { int sign=0; for(int i=5;i<=s.length;i++) { if(!number(s[i-1])){System.out.println("wrong format");sign++;} } if((m.get(s[0])!=null&&m.get(s[0]).equalsIgnoreCase(s[2]))||sign!=0)continue; number = s[0]; studentname = s[1]; Student student; Course course ; Class c ; c=classes.get(s[0].substring(0,6)); if(c==null)c=new Class(); student= students.get(s[0]); if(student==null)student=new Student(); student.name = studentname; student.number = number; course = corses.get(s[2]); if(course==null) { student.i--; System.out.println(s[2]+" does not exist"); } else {double sum=0;int i=4,j=0; for(;i<=s.length;i++) { sum+=Integer.parseInt(s[i-1])*course.a[i-4]; j++; } if(course.j!=j) { System.out.println(number + " " + studentname + " : access mode mismatch"); students.put(s[0], student); classes.put(s[0].substring(0,6), c);continue;} course.score+=sum; student.score+=sum; } c.number=s[0].substring(0,6); student.i++; students.put(s[0], student); if(course!=null){ course.i++; corses.put(course.name, course);} classes.put(c.number, c); m.put(s[0],s[2]); continue; }实验课程信息的输入
首先,代码中使用了一个 for 循环来遍历字符串数组 s
,循环的起始位置是 5,终止位置是 s.length
。在循环体内,通过判断 s[i-1]
是否为数字,如果不是数字则输出 "wrong format" 并将 sign
增加 1。
接下来是一个条件判断语句,判断 m.get(s[0])
是否为空并且与 s[2]
忽略大小写后的值相等,或者 sign
不等于 0。如果满足条件,则执行 continue
,即跳过本次循环。
如果条件判断不满足,则代码继续执行。接着将 s[0]
赋值给 number
,将 s[1]
赋值给 studentname
。然后定义了两个对象:student
和 course
。
接下来是对 c
的操作,首先根据 s[0]
的前 6 位获取到 classes
中的值赋给 c
。如果 c
为 null,则新建一个 Class
对象。然后根据 s[0]
获取 students
中的值赋给 student
,如果 student
为 null,则新建一个 Student
对象。
然后将 studentname
赋值给 student
的 name
属性,将 number
赋值给 student
的 number
属性。
接下来根据 s[2]
获取 corses
中的值赋给 course
。如果 course
为 null,则将 student
的 i
减 1,并输出 "s[2] does not exist"。否则,执行以下逻辑:
- 定义变量
sum
并初始化为 0,定义变量i
和j
并初始化为 4。 - 进入一个 for 循环,循环条件是
i <= s.length
。- 将
s[i-1]
转换为整数并乘以course.a[i-4]
,然后累加到sum
中。 - 将
j
增加 1。
- 将
- 判断
course.j
是否等于j
,如果不相等,则输出number + " " + studentname + " : access mode mismatch"
,将student
和c
分别放回students
和classes
中,并执行continue
,跳过本次循环。 - 将
sum
累加到course.score
和student.score
中。
最后,将 s[0]
的前 6 位赋值给 c.number
,将 student.i
增加 1。然后将 student
存入 students
,如果 course
不为 null,则将 course.i
增加 1,并将 course
存入 corses
。最后将 s[0]
和 s[2]
存入 m
中。
整个代码片段的功能可能是对学生选课和成绩统计进行处理,包含了对输入格式的检查、数据的更新和输出信息的打印等操作。但由于给出的代码片段不完整且缺少上下文,无法准确判断其完整功能和用途。需要提供更多背景信息才能进行更具体的分析和解释。
(3).踩坑心得:
1.在程序的输出中,是需要把所有的数据一起加和后进行四舍五入,而不是分别四舍五入后进行求和
2.超出范围的返回值错误,导致返回空。
3.进行数据储存的时候,list之类确实要比数组之类的好用很多。
(4).改进建议:
对相应题目的编码改进给出自己的见解,做到可持续改进
我在课程题目中没有对数据进行统一,比如班级中的学生,课程中的学生,学生的课程,都是分开存的数据,导致我的主函数存数据时代码很长。我希望可以实现数据的统一存储。
(5).总结:
本学期的面向对象课程已经结束,重点学习了设计理念和原则以及一些集合容器的使用,强调了面向对象的封装、继承和多态三大特性。未来的学习中,我们将进一步深化设计理念,尽可能符合设计原则。本课程采用了线上与线下相结合的教学模式,采用了边讲边练的教学方式,以及翻转课堂的教学方法,这些都非常好。我们还将课程内容与现实生活中的例子相结合,例如雨刷系统和JavaFx动画实现,以帮助学生更好地巩固所学知识,并将理论应用于实际项目中。
然而,在PTA或实验中,学生的问题反馈较少。我们可以适当提供一些思路或细节上的提示,帮助学生提高代码质量和设计思路,而不仅仅是面向过程、结果编程。如果时间允许,我们还可以提供更多类似于翻转课堂和小组合作的课程内容,引导学生并提高他们的自学能力和集体感,使他们更积极地参与到课堂中来。
标签:总结,题目,String,number,PTA,course,课程,student,成绩 From: https://www.cnblogs.com/zrs2768371622/p/17511060.html