前言

本次博客针对面向对象程序设计的课程所发的PTA作业7,8以及期末考试中的面向对象编程题的分析和总结,重点介绍课程成绩统计程序系列题目以及期末考试的编程题。

PTA第七次作业

在这次作业中7-1、7-2内容和考点相同,在此我分析一下7-2Hashmap的排序这个问题。

7-2 容器-HashMap-排序
分数 10
作者 蔡轲
单位 南昌航空大学

输入多个学生的成绩信息,包括:学号、姓名、成绩。

学号是每个学生的唯一识别号,互不相同。

姓名可能会存在重复。

要求:使用HashMap存储学生信息。

输入格式:

输入多个学生的成绩信息,每个学生的成绩信息格式:学号+英文空格+姓名+英文空格+成绩

以“end”为输入结束标志

输出格式:

按学号从大到小的顺序输出所有学生信息,每个学生信息的输出格式:学号+英文空格+姓名+英文空格+成绩

输入样例:

在这里给出一组输入。例如:

20201124 张少军 83
20201136 李四 78
20201118 郑觉先 80
end

输出样例:

在这里给出相应的输出。例如:

20201136 李四 78
20201124 张少军 83
20201118 郑觉先 80
这道题目的考点在于Hashmap容器的使用以及排序函数的使用,我的源代码如下:
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        HashMap<String,String> hashMap = new HashMap<String,String>();
        while(true)
        {
            String str  =  input.nextLine();
            if(str.equals("end"))
            {
                break;
            }
            String str1[] = str.split(" ");
            String no = str1[0];
            String name = str1[1];
            String grade = str1[2];
            hashMap.put(no,name+" "+grade);
        }
        List<String> studentIds = new ArrayList<>(hashMap.keySet());

        // 按学号从大到小排序
        Collections.sort(studentIds, (s1, s2) -> Integer.parseInt(s2) - Integer.parseInt(s1));

        // 输出学生信息
        for (String studentId : studentIds) {
            String studentInfo = hashMap.get(studentId);
            System.out.println(studentId + " " + studentInfo);
        }
    }
}
排序
 

  本次的代码较短且复杂度很低,在此不赘述其类图以及圈复杂度分析。

这次作业中难度较大的是课程成绩统计程序-2,下面是这道题目的介绍和分析。

7-3 课程成绩统计程序-2
分数 60
作者 蔡轲
单位 南昌航空大学

课程成绩统计程序-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)成绩平均分只取整数部分,小数部分丢弃

参考类图(与第一次相同,其余内容自行补充):


e724fa4193aa9ee32e78a68cd96fd6df_22401e04-c501-4b28-bb65-dabe39d374e7.png

 

输入样例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

这个题目是课程成绩统计程序-1的升级,添加了实验课的部分,修改了一部分输入输出以及错误的输出,总体来说相比较第一次改动不大,以下是我的代码:
  1 import java.util.*;
  2 import java.text.Collator;
  3 class Crouse{
  4     String name;
  5     String nature;
  6     String fangshi;
  7     ArrayList<Integer> pgrade = new ArrayList<>();
  8     ArrayList<Integer> qgrade = new ArrayList<>();
  9   ArrayList<Integer> grade = new ArrayList<>();
 10     public Crouse(String name, String nature, String fangshi) {
 11         this.name = name; // 将参数赋值给成员变量
 12         this.nature = nature; // 将参数赋值给成员变量
 13         this.fangshi = fangshi; // 将参数赋值给成员变量
 14     }
 15     public int average()
 16     {
 17         int total=0;
 18         for (int i:grade)
 19         {
 20             total+=i;
 21         }
 22         return total/grade.size();
 23     }
 24     public int average1()
 25     {
 26         int total=0;
 27         for (int i:pgrade)
 28         {
 29             total+=i;
 30         }
 31         return total/pgrade.size();
 32     }
 33     public int average2()
 34     {
 35         int total=0;
 36         for (int i:qgrade)
 37         {
 38             total+=i;
 39         }
 40         return total/qgrade.size();
 41     }
 42 
 43 }
 44 class Student {
 45     String id;
 46     String name;
 47     HashMap<String,Integer> crouse;
 48     public Student(String id, String name) {
 49         this.id = id; // 将参数赋值给成员变量
 50         this.name = name; // 将参数赋值给成员变量
 51         this.crouse = new HashMap<>();
 52     }
 53     public int averagegrade()
 54     {
 55         int total=0;
 56         for (Integer grade:crouse.values()) {
 57             total += grade;
 58         }
 59         return total/ crouse.size();
 60     }
 61 }
 62 class Class{
 63     String cid;
 64     ArrayList<Student> students = new ArrayList<>();
 65     public Class(String cid)
 66     {
 67         this.cid=cid;
 68     }
 69     public int average()
 70     {
 71         int total=0;
 72         for (Student s:students)
 73         {
 74             total+=s.averagegrade();
 75         }
 76         return total/students.size();
 77     }
 78 }
 79 class Holder{
 80     ArrayList<Crouse> clist = new ArrayList<>();
 81     ArrayList<Student> slist = new ArrayList<>();
 82     ArrayList<Class> Clist = new ArrayList<>();
 83 
 84     public Crouse searth(String name)
 85     {
 86         int falg =0;
 87         int i;
 88         for ( i = 0; i < clist.size(); i++) {
 89             if(clist.get(i).name.equals(name))
 90             {
 91                 falg++;
 92                 break;
 93             }
 94         }
 95         if(falg!=0)
 96         {
 97             return clist.get(i);
 98         }
 99         else return null;
100     }
101 }
102 public class Main {
103     public static void main(String[] args) {
104         Scanner input = new Scanner(System.in);
105         Holder holder = new Holder();
106         while (true) {
107             try {
108                 String str = input.nextLine();
109                 if (str.equals("end")) {
110                     break;
111                 }
112                 String[] str1 = str.split(" ");
113                 if (str1.length == 3) {
114                     if (str1[1].equals("必修")) {
115                         if (str1[2].equals("考试")) {
116                             String name = str1[0];
117                             String nature = str1[1];
118                             String fangshi = str1[2];
119                             Crouse crouse = null;
120                             for (Crouse c:holder.clist)
121                             {
122                                 if(c.name.equals(name)) {
123                                     crouse = c;
124                                     break;
125                                 }
126                             }
127                             if(crouse==null) {
128                                 crouse = new Crouse(name, nature, fangshi);
129                                 holder.clist.add(crouse);
130                             }
131                         } else {
132                             System.out.println(str1[0] + " : course type & access mode mismatch");
133                         }
134                     } else if (str1[1].equals("选修")) {
135                         if (str1[2].equals("考试")) {
136                             String name = str1[0];
137                             String nature = str1[1];
138                             String fangshi = str1[2];
139                             Crouse crouse = null;
140                             for (Crouse c:holder.clist)
141                             {
142                                 if(c.name.equals(name)) {
143                                     crouse = c;
144                                     break;
145                                 }
146                             }
147                             if(crouse==null) {
148                                 crouse = new Crouse(name, nature, fangshi);
149                                 holder.clist.add(crouse);
150                             }
151                         } else if (str1[2].equals("考察")) {
152                             String name = str1[0];
153                             String nature = str1[1];
154                             String fangshi = str1[2];
155                             Crouse crouse = null;
156                             for (Crouse c:holder.clist)
157                             {
158                                 if(c.name.equals(name)) {
159                                     crouse = c;
160                                     break;
161                                 }
162                             }
163                             if(crouse==null) {
164                                 crouse = new Crouse(name, nature, fangshi);
165                                 holder.clist.add(crouse);
166                             }
167                         } else {
168                             System.out.println(str1[0] + " : course type & access mode mismatch");
169                         }
170                     } else if (str1[1].equals("实验")) {
171                         if (str1[2].equals("实验")) {
172                             String name = str1[0];
173                             String nature = str1[1];
174                             String fangshi = str1[2];
175                             Crouse crouse = null;
176                             for (Crouse c:holder.clist)
177                             {
178                                 if(c.name.equals(name)) {
179                                     crouse = c;
180                                     break;
181                                 }
182                             }
183                             if(crouse==null) {
184                                 crouse = new Crouse(name, nature, fangshi);
185                                 holder.clist.add(crouse);
186                             }
187                         } else {
188                             System.out.println(str1[0] + " : course type & access mode mismatch");
189                         }
190                     }
191                 } else if (str1.length == 4)//选修,考察
192                 {
193                     if (Integer.parseInt(str1[3]) > 0 && Integer.parseInt(str1[3]) < 100) {
194                         if (holder.searth(str1[2]) != null) {
195                             String stuid = str1[0];
196                             String sname = str1[1];
197                             if (holder.searth(str1[2]).nature.equals("选修")) {
198                                 Student student = null;
199                                 for (Student s:holder.slist)
200                                 {
201                                     if(s.name.equals(sname))
202                                     {
203                                         student = s;
204                                         break;
205                                     }
206                                 }
207                                 String cid = stuid.substring(0, 6);
208                                 Class cla = null;
209                                 for (Class c : holder.Clist) {
210                                     if (c.cid.equals(cid)) {
211                                         cla = c;
212                                         break;
213                                     }
214                                 }
215                                 if (cla == null) {
216                                     cla = new Class(cid);
217                                     holder.Clist.add(cla);
218                                 }
219                                 if(student==null) {
220                                     student = new Student(stuid,sname);
221                                     student.crouse.put(str1[2], Integer.parseInt(str1[3]));
222                                     cla.students.add(student);
223                                     holder.slist.add(student);
224                                     holder.searth(str1[2]).grade.add(Integer.parseInt(str1[3]));
225                                 }
226                                 else {
227                                     student.crouse.put(str1[2], Integer.parseInt(str1[3]));
228                                     holder.searth(str1[2]).grade.add(Integer.parseInt(str1[3]));
229                                 }
230                             } else
231                                 System.out.println(stuid + " " + sname + " " + ": access mode mismatch");
232                         } else
233                             System.out.println(str1[0] + " " + str1[1] + " " + ":" + str1[2] + " " + "does not exist");
234                     } else System.out.println("wrong format");
235                 } else if (str1.length == 5)//必修或选修考试
236                 {
237                     if (holder.searth(str1[2]) != null) {
238                         String stuid = str1[0];
239                         String sname = str1[1];
240                         int grade = (int) (Integer.parseInt(str1[3]) * 0.3 + Integer.parseInt(str1[4]) * 0.7);
241                         Student student = null;
242                         for (Student s:holder.slist)
243                         {
244                             if(s.name.equals(sname))
245                             {
246                                 student = s;
247                                 break;
248                             }
249                         }
250 
251                         String cid = stuid.substring(0, 6);
252                         Class cla = null;
253                         for (Class c : holder.Clist) {
254                             if (c.cid.equals(cid)) {
255                                 cla = c;
256                                 break;
257                             }
258                         }
259                         if (cla == null) {
260                             cla = new Class(cid);
261                             holder.Clist.add(cla);
262                         }
263                         if(student==null) {
264                             student = new Student(stuid,sname);
265                             student.crouse.put(str1[2], grade);
266                             cla.students.add(student);
267                             holder.slist.add(student);
268                             holder.searth(str1[2]).grade.add(grade);
269                             holder.searth(str1[2]).pgrade.add(Integer.parseInt(str1[3]));
270                             holder.searth(str1[2]).qgrade.add(Integer.parseInt(str1[4]));
271                         }
272                         else {
273                             student.crouse.put(str1[2], grade);
274                             holder.searth(str1[2]).grade.add(grade);
275                             holder.searth(str1[2]).pgrade.add(Integer.parseInt(str1[3]));
276                             holder.searth(str1[2]).qgrade.add(Integer.parseInt(str1[4]));
277                         }
278                     } else
279                         System.out.println(str1[0] + " " + str1[1] + " " + ":" + str1[2] + " " + "does not exist");
280                 } else if (Integer.parseInt(str1[3]) > 3 && Integer.parseInt(str1[3]) < 10)//实验
281                 {
282                     int num = Integer.parseInt(str1[3]);
283                     int falg = 0;
284                     for (int i = 4; i < str1.length; i++) {
285                         if (Integer.parseInt(str1[i]) < 0 || Integer.parseInt(str1[i]) > 100)
286                             falg++;
287                     }
288                     if (falg == 0) {
289                         if (holder.searth(str1[2]) != null) {
290                             String stuid = str1[0];
291                             String sname = str1[1];
292                             int grade = 0;
293                             if (str1.length == 4 + num) {
294                                 for (int i = 4; i < 4 + num; i++) {
295                                     grade += Integer.parseInt(str1[i]);
296                                 }
297                                 grade = grade / 4;
298                                 Student student = null;
299                                 for (Student s:holder.slist)
300                                 {
301                                     if(s.name.equals(sname))
302                                     {
303                                         student = s;
304                                         break;
305                                     }
306                                 }
307                                 String cid = stuid.substring(0, 6);
308                                 Class cla = null;
309                                 for (Class c : holder.Clist) {
310                                     if (c.cid.equals(cid)) {
311                                         cla = c;
312                                         break;
313                                     }
314                                 }
315                                 if (cla == null) {
316                                     cla = new Class(cid);
317                                     holder.Clist.add(cla);
318                                 }
319                                 if(student==null) {
320                                     student = new Student(stuid,sname);
321                                     student.crouse.put(str1[2], grade);
322                                     cla.students.add(student);
323                                     holder.slist.add(student);
324                                     holder.searth(str1[2]).grade.add(grade);
325                                 }
326                                 else {
327                                     student.crouse.put(str1[2], grade);
328                                     holder.searth(str1[2]).grade.add(grade);
329                                 }
330                             } else {
331                                 Student student = new Student(stuid, sname);
332                                 String cid = stuid.substring(0, 6);
333                                 Class cla = null;
334                                 for (Class c : holder.Clist) {
335                                     if (c.cid.equals(cid)) {
336                                         cla = c;
337                                         break;
338                                     }
339                                 }
340                                 if (cla == null) {
341                                     cla = new Class(cid);
342                                     holder.Clist.add(cla);
343                                 }
344                                 holder.slist.add(student);
345                                 System.out.println(stuid + " " + sname + " " + ": access mode mismatch");
346                             }
347                         } else
348                             System.out.println(str1[0] + " " + str1[1] + " " + ":" + str1[2] + " " + "does not exist");
349                     } else System.out.println("wrong format");
350                 } else
351                     System.out.println("wrong format");
352             }
353             catch (NumberFormatException e)
354             {
355                 System.out.println("wrong format");
356             }
357         }
358 
359         holder.slist.sort(Comparator.comparing(s -> s.id));
360         for(Student student:holder.slist)
361         {
362             if(student.crouse.isEmpty())
363             {
364                 System.out.println(student.id+" "+student.name+" "+"did not take any exams");
365             }
366             else  System.out.println(student.id+" "+student.name+" "+student.averagegrade());
367         }
368 
369         Collator collator = Collator.getInstance();
370         holder.clist.sort(Comparator.comparing(c -> c.name, collator));
371         for(Crouse crouse:holder.clist)
372         {
373             if(crouse.grade.isEmpty())
374             {
375                 System.out.println(crouse.name+" "+"has no grades yet");
376             }
377             else if(crouse.nature.equals("选修")&&crouse.fangshi.equals("考察"))
378                 System.out.println(crouse.name+" "+crouse.average()+" "+crouse.average());
379             else if(crouse.nature.equals("选修")&&crouse.fangshi.equals("考试"))
380                 System.out.println(crouse.name+" "+crouse.average1()+" "+crouse.average2()+" "+crouse.average());
381             else if(crouse.nature.equals("必修"))
382                 System.out.println(crouse.name+" "+crouse.average1()+" "+crouse.average2()+" "+crouse.average());
383             else if(crouse.nature.equals("实验"))
384                 System.out.println(crouse.name+" "+crouse.average());
385         }
386         holder.Clist.sort(Comparator.comparing(c -> c.cid));
387         for(Class c:holder.Clist)
388         {
389             int falg=0;
390             for (Student s: c.students)
391             {
392                 if(s.averagegrade()==0)
393                 {
394                     falg++;
395                 }
396             }
397             if(falg==c.students.size())
398             {
399                 System.out.println(c.cid+" "+ "has no grades yet");
400             }
401             else
402                 System.out.println(c.cid+" "+c.average());
403         }
404     }
405 }

  Crouse类表示课程,包含课程名称、课程性质、考核方式以及成绩列表。Student类表示学生,包含学号、姓名和课程成绩的映射关系。Class类表示班级,包含班级号和学生列表。我用了一个holder类储存课程链表、成绩链表、以及班级链表,进而在Main类中通过循环输出课程的平均成绩、学生的平均成绩、班级的平均成绩以及对无成绩的情况输出。

该代码的类图如下:

 

用source moniter分析圈复杂度情况如下:

从圈复杂度以及代码深度分析图可以看出,我的代码最大复杂性为91,平均复杂度为10.90,根据基维亚特图可以看出我的代码复杂度较高,平均运行时间长。

 


PTA第八次作业

 

7-2 课程成绩统计程序-3
分数 64
作者 蔡轲
单位 南昌航空大学

课程成绩统计程序-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)成绩平均分只取整数部分,小数部分丢弃

参考类图(与第一次相同,其余内容自行补充):

fdada4ca193119ee30531ab82ffebbfa_9dbcf4e8-1627-4cf6-8764-cccf44947e2a.png

输入样例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

这道题目是对课程成绩统计程序-2的升级,主要添加了实验课的成绩权重部分,将原来的平均模式改为了加权平均算法,并且改成了在课程信息中输入实验次数及权重,修改
了一部分输入输出以及错误的输出。
我的代码如下:
  1 import java.util.*;
  2 import java.text.*;
  3 public class Main {
  4     public static void main(String[] args) {
  5         Scanner scanner = new Scanner(System.in);
  6         Input_Format inputFormat = new Input_Format();//输入
  7         Output_Format outputFormat = new Output_Format();//输出
  8         Data_storage data_storage = new Data_storage();
  9         while (inputFormat.isEnd){
 10             String inputLine = scanner.nextLine();
 11             if(inputLine.equals("end")){
 12                 inputFormat.isEnd = false;
 13                 break;
 14             }
 15             inputFormat.inputProcessing(inputLine,data_storage);
 16         }
 17         PersonOverride student1 = new PersonOverride();
 18         outputFormat.outputProcessing(data_storage);
 19         outputFormat.output_all(data_storage);
 20     }
 21 }
 22 class Calculate_grades {
 23     int stu_all_grades(Data_storage data_storage,String num){//单个学生总课程平均分计算  返回一个分数 1)
 24         int count =0;//这个学生有几门课
 25         int sum = 0;
 26         for (Map.Entry<String, Score> entry : data_storage.stu__st_cour.get(num).gradeMap.entrySet()) {
 27             Score value = entry.getValue();
 28             if(Integer.parseInt(value.total_scores)>=0) {
 29                 count++;
 30                 sum += Integer.parseInt(value.total_scores);
 31             }
 32         }
 33         if(count!=0)
 34             return sum/count;
 35         else
 36             return -100;//没有参加任何考试
 37     }
 38     int[] single_course_grades(Data_storage data_storage,String name){ //2) 课程名
 39         int count = 0;
 40         int[] aver_grade = new int[3];//0:平时成绩 1:期末考试 2:总分平均
 41         for (Map.Entry<String, StudentsAll_mes> e : data_storage.stu__st_cour.entrySet()) {//遍历选课类:num-选课类
 42             StudentsAll_mes value = e.getValue();
 43             for (Map.Entry<String, Score> entry : value.gradeMap.entrySet()) {//遍历选课类:course.name-Score
 44                 String key1 = entry.getKey();
 45                 Score value1 = entry.getValue();
 46                 if (key1.equals(name)) {
 47                     if(Integer.parseInt(value1.total_scores)>=0) {//总分为- 说明算成绩无效
 48                         count++;
 49                         aver_grade[2] += Integer.parseInt(value1.total_scores);
 50                         if (value1 instanceof Test_Score) {
 51                             if (Integer.parseInt(value1.total_scores) >= 0) {
 52                                 aver_grade[0] += Integer.parseInt(((Test_Score) value1).normal_score);
 53                                 aver_grade[1] += Integer.parseInt(((Test_Score) value1).end_score);
 54                             }
 55                         } else if (value1 instanceof Inspect_Score){
 56                             if (Integer.parseInt(value1.total_scores) >= 0) {
 57                                 aver_grade[0] = -100;//不需要平时成绩
 58                                 aver_grade[1] += Integer.parseInt(((Inspect_Score) value1).end_score);
 59                             }
 60                         }else if(value1 instanceof Lab_Score){
 61                             if(Integer.parseInt(value1.total_scores)>=0){
 62                                 aver_grade[0] = -100;
 63                                 aver_grade[1] += aver_grade[1] += Integer.parseInt(value1.total_scores);
 64                             }
 65                         }
 66                     }
 67                 }
 68             }
 69         }
 70         if(count!=0) {
 71             for (int i = 0; i < 3; i++) {
 72                 aver_grade[i] = aver_grade[i] / count;
 73             }
 74         }else {
 75             for (int i = 0; i < 3; i++) {
 76                 aver_grade[i] = -100;
 77             }
 78         }
 79         return aver_grade;
 80     }
 81     int Class_grades(Data_storage data_storage,String num){//3)
 82         int sum = 0;
 83         int count = 0;
 84         for (Map.Entry<String, Student> mapEntry : data_storage.classes.get(num).students.entrySet()) {//班级号-Student类
 85             Student value = mapEntry.getValue();//遍历这个班级的所有学生
 86             for (Map.Entry<String, StudentsAll_mes> e : data_storage.stu__st_cour.entrySet()) {//stu_num-选课类
 87                 String key1 = e.getKey();//遍历学生的选课类 学号
 88                 StudentsAll_mes value1 = e.getValue();
 89                 if (key1.equals(value.num)) {//选课类中 跟输入的学号一样
 90                     for (Map.Entry<String, Score> entry : value1.gradeMap.entrySet()) {//该num所有成绩遍历
 91                         Score gra = entry.getValue();
 92                         if(Integer.parseInt(gra.total_scores)>=0) {//有效才算
 93                             sum += Integer.parseInt(gra.total_scores);
 94                             count++;
 95                         }
 96                     }
 97                 }
 98             }
 99         }
100         if(count!=0)
101             return sum/count;
102         else
103             return -100;
104     }
105     void final_score(Data_storage data_storage,String num){//计算没门课的成绩 学号
106         data_storage.stu__st_cour.get(num).gradeMap.forEach((key,value)->{//学号  成绩
107             if(value instanceof Test_Score&&((Test_Score) value).normal_score.matches("\\d+")&&((Test_Score) value).end_score.matches("\\d+")) {
108                 double tem = ((Test_Course) data_storage.courses.get(key)).normal_weight*Integer.parseInt(((Test_Score) value).normal_score);
109                 double tem1 = ((Test_Course) data_storage.courses.get(key)).end_weight*Integer.parseInt(((Test_Score) value).end_score);
110                 value.total_scores = String.valueOf((int)(tem+tem1));
111             }else if(value instanceof Inspect_Score&&((Inspect_Score) value).end_score.matches("\\d+")){
112                 value.total_scores = ((Inspect_Score) value).end_score;
113             }else if(value instanceof Lab_Score&&((Lab_Score) value).lab_num.matches("\\d+")){
114                 float sum = 0;
115                 int i=0;
116                 for (Integer score : ((Lab_Score) value).scores) {
117                     sum+= score* ((Lab_Course) data_storage.courses.get(key)).weights.get(i);
118                     i++;
119                 }
120                 value.total_scores = String.valueOf((int)sum);
121             }
122         });
123     }
124 }
125 class PersonOverride {
126     private String name;
127     private int age;
128     private boolean gender;
129 
130     public PersonOverride() {
131         this("default", 1, true);
132     }
133 
134     public PersonOverride(String name, int age, boolean gender) {
135         this.name = name;
136         this.age = age;
137         this.gender = gender;
138     }
139 
140     @Override
141     public String toString() {
142         return name + "-" + age + "-" + gender;
143     }
144 }
145 class Class {
146     String num;
147     TreeMap<String, Student> students = new TreeMap<>(); //班级里的学生 学号 学生
148     Class(String num){
149         this.num = num;
150     }
151 }
152 class Course {
153     String type;
154     String test_way;
155     String name;
156     Course(String name,String type, String test_way){
157         this.type = type;
158         this.name = name;
159         this.test_way = test_way;
160     }
161 }
162 class Inspect_Course extends Course{
163     Inspect_Course(String name, String type, String test_way) {
164         super(name, type, test_way);
165     }
166 }
167 
168 class Test_Course extends Course{
169     double normal_weight;
170     double end_weight;
171 
172     Test_Course(String name, String type, String test_way,String normal_weight,String end_weight) {
173         super(name, type, test_way);
174         this.normal_weight = Float.parseFloat(normal_weight);
175         this.end_weight = Float.parseFloat(end_weight);
176     }
177 }
178 class Lab_Course extends Course{
179     int sub_scores_num;
180     ArrayList<Float> weights = new ArrayList<>();
181     Lab_Course(String name, String type, String test_way,String line) {
182         super(name, type, test_way);
183         String[] lines = line.split(" ");
184         sub_scores_num = Integer.parseInt(lines[3]);
185         for(int i=4;i<lines.length; i++){
186             weights.add(Float.parseFloat(lines[i]));
187         }
188     }
189 }
190 class Data_storage {
191     TreeMap<String , Course> courses;//课程  k:课程名 v:课程
192     TreeMap<String, Class> classes = new TreeMap<>();//班级 k:班级号V:班级
193     TreeMap<String, StudentsAll_mes> stu__st_cour;//选课类学生类结合 k:学号 v:选课类
194     InAndOut_put output = new InAndOut_put();
195     Data_storage(){
196         //学生和选课类结合
197         stu__st_cour = new TreeMap<>(Data_storage::compare);//重写排序
198         courses = new TreeMap<>(Data_storage::compare);
199     }
200 
201     private static int compare(String o1, String o2) {
202 
203         try {
204             Comparator<Object> comparator = Collator.getInstance(Locale.CHINA);
205             if (comparator.compare(o1, o2) < 0) {
206                 return -1;
207             } else if (comparator.compare(o1, o2) > 0) {
208                 return 1;
209             }
210         } catch (Exception ignored) {
211         }
212         return 0;
213     }
214 
215     void setInspectCourses(String name, String type, String test_way){
216         if(!courses.containsKey(name)) {
217             courses.put(name, new Inspect_Course(name, type, test_way));
218         }
219     }
220     void setTestCourses(String name, String type, String test_way,String normal_weight, String end_weight){
221         if(!courses.containsKey(name)) {
222             courses.put(name, new Test_Course(name, type, test_way,normal_weight, end_weight));
223         }
224     }
225     void setLabCourses(String name, String type, String test_way,String line){
226         if(!courses.containsKey(name)) {
227             courses.put(name, new Lab_Course(name, type, test_way,line));
228         }
229     }
230     void setClasses(String num){
231         if(!classes.containsKey(num)) {
232             classes.put(num, new Class(num));
233         }
234     }
235     void setStudents(String clas_num, String name, String num){//班级号 姓名 学号
236         if(classes.containsKey(clas_num)){
237             if(!classes.get(clas_num).students.containsKey(num))
238                 classes.get(clas_num).students.put(num,new Student(name,num));
239         }
240     }
241     void setStu__st_courAndMap(String num,String course,String normal_score,String end_score){//添加选课类  学生姓名 课程名称 分数
242         if(!stu__st_cour.containsKey(num)){
243             stu__st_cour.put(num,new StudentsAll_mes(num,course,normal_score,end_score));
244         }
245         else{
246             stu__st_cour.get(num).setGradeMap(course,normal_score,end_score);
247         }
248     }
249     void setStu__st_courAndMap(String num,String course,String end_score){
250         if(!stu__st_cour.containsKey(num)){
251             stu__st_cour.put(num,new StudentsAll_mes(num,course,end_score));
252         }
253         else{
254             stu__st_cour.get(num).setGradeMap(course,end_score);
255         }
256     }
257     void set_lab_grades(String stu_num,String course,String lab_num,String grades){
258         ArrayList<Integer> scores = new ArrayList<>();
259         String[] tem = grades.split(" ");
260         for(int i=3;i<tem.length;i++){
261             if(tem[i].matches("\\d+"))
262                 scores.add(Integer.parseInt(tem[i]));
263         }
264         if(!stu__st_cour.containsKey(stu_num)){
265             StudentsAll_mes tem_stu_mes = new StudentsAll_mes();
266             tem_stu_mes.set_lab_stu_mes(stu_num,course,lab_num,scores);
267             stu__st_cour.put(stu_num,tem_stu_mes);
268         }else{
269             stu__st_cour.get(stu_num).set_lab_gradeMap(course,lab_num,scores);
270         }
271     }
272 }
273 class Input_Format {
274     String regex_c_test = "^[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s(必修|选修)\\s考试\\s((0.\\d{1,2})|(1-9?))\\s((0.\\d{1,2})|(1-9?))$";
275     String regex_c_inspect = "[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s选修\\s考察$";
276     String regex_c_lab = "^[\\u4e00-\\u9fa5a-zA-Z0-9 ]{1,10}\\s实验\\s实验\\s[4-9]\\s((0.\\d{1,2})|(1-9?))(\\s((0.\\d{1,2})|(1-9?))){3,9}$";
277     String regex_CS = "^\\d{8}\\s+[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s+[\\u4E00-\\u9FA5A-Za-z0-9]{1,10}\\s*((100)|(\\d{1,2})|(0))?\\s+((100)|(\\d{1,2})|(0))$";
278     String regex_lab = "^\\d{8}\\s[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s[\\u4e00-\\u9fa5a-zA-Z0-9 ]{1,10}\\s((100)|([1-9]\\d)|\\d)(\\s((100)|([1-9]\\d)|\\d)){2,9}$";
279     boolean isEnd = true;//结束标志
280     String[] strings;
281     void inputProcessing(String line,Data_storage data_storage) {
282         lineProcessing(line);//分割
283         data_storage.output.add_input(line);//存储
284         if(line.matches(regex_c_inspect)){
285             data_storage.setInspectCourses(strings[0],strings[1],strings[2]);
286         }else if(line.matches(regex_c_lab)){
287             data_storage.setLabCourses(strings[0],strings[1],strings[2],line);
288         }else if(line.matches(regex_c_test)){
289             data_storage.setTestCourses(strings[0],strings[1],strings[2],strings[3],strings[4]);//成绩信息
290         } else if(line.matches(regex_CS)||line.matches(regex_lab)){
291             data_storage.setClasses(strings[0].substring(0,6));
292             data_storage.setStudents(strings[0].substring(0, 6), strings[1], strings[0]);//学生的添加
293             if (data_storage.courses.containsKey(strings[2])) {//课程里有这个课
294                 if (data_storage.courses.get(strings[2]).type.equals("选修")) {//
295                     if (data_storage.courses.get(strings[2]).test_way.equals("考试")&&strings.length == 5) {
296                         data_storage.setStu__st_courAndMap(strings[0], strings[2], strings[3], strings[4]);
297                     }else if(data_storage.courses.get(strings[2]).test_way.equals("考察")&&strings.length==4){
298                         data_storage.setStu__st_courAndMap(strings[0], strings[2], strings[3]);
299                     } else {
300                         data_storage.setStu__st_courAndMap(strings[0], strings[2], "no access", "no access");
301                     }
302                 } else if (data_storage.courses.get(strings[2]).type.equals("必修")) {//
303                     if (strings.length == 5) {
304                         data_storage.setStu__st_courAndMap(strings[0], strings[2], strings[3],strings[4]);
305                     } else {//无效
306                         data_storage.setStu__st_courAndMap(strings[0], strings[2], "no access", "no access");
307                     }
308                 } else if(data_storage.courses.get(strings[2]).type.equals("实验")){
309                     if(strings.length == 3+((Lab_Course) data_storage.courses.get(strings[2])).sub_scores_num){
310                         data_storage.set_lab_grades(strings[0],strings[2], String.valueOf(((Lab_Course) data_storage.courses.get(strings[2])).sub_scores_num),line);
311                     }else{
312                         data_storage.set_lab_grades(strings[0],strings[2],"num error","no access");
313                     }
314                 }
315             }else{
316                 data_storage.setStu__st_courAndMap(strings[0], strings[2], "not exist");
317             }
318         }
319     }
320     void lineProcessing(String line){
321         strings = line.split(" ");
322     }
323 }
324 class Inspect_Score extends Score{
325     String end_score;
326     Inspect_Score(String end_score) {
327         this.end_score = end_score;
328     }
329 }
330 class  Output_Format {
331     Calculate_grades calculate = new Calculate_grades();
332     String regex_c_test = "^[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s(必修|选修|实验)\\s(考试|考察|实验)\\s((\\d{1,2})|(1-9?))\\s((\\d{1,2})|(1-9?))$";
333     String regex_c_test_e = "^[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s(必修|选修|实验)\\s(考试|考察|实验)\\s((0.\\d{1,2})|(1-9?))\\s((0.\\d{1,2})|(1-9?))$";
334     String regex_c_inspect = "[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s(必修|选修|实验)\\s(考试|考察|实验)$";
335     String regex_c_lab = "^[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s(必修|选修|实验)\\s(考试|考察|实验)\\s[4-9]\\s((0.\\d{1,2})|(1-9?))(\\s((0.\\d{1,2})|(1-9?))){1,10}$";
336     String regex_CS = "^\\d{8}\\s+[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s+[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s*((100)|(\\d{1,2})|(0))?\\s+((100)|(\\d{1,2})|(0))$";
337     String regex_lab = "^\\d{8}\\s[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s[\\u4e00-\\u9fa5a-zA-Z0-9]{1,10}\\s((100)|([1-9]\\d)|\\d)(\\s((100)|([1-9]\\d)|\\d)){1,20}$";
338     void outputProcessing(Data_storage data) {
339         data.classes.forEach((num,Class)-> Class.students.forEach((name, student)-> calculate.final_score(data,student.num)));
340         for(String i:data.output.input){
341             String[] tem = i.split(" ");
342             if(i.matches(regex_c_test_e)||i.matches(regex_c_test)||i.matches(regex_c_inspect)||i.matches(regex_c_lab)){
343                 if(tem[1].equals("必修")&&(tem[2].equals("考察")||tem[2].equals("实验"))){
344                     data.output.add_output(tem[0] + " : course type & access mode mismatch");
345                 }else if(tem[1].equals("实验")&&!tem[2].equals("实验")) {
346                     data.output.add_output(tem[0] + " : course type & access mode mismatch");
347                 }else if(tem[1].equals("选修")&&tem[2].equals("实验")) {
348                     data.output.add_output(tem[0] + " : course type & access mode mismatch");
349                 }
350                 if(tem[1].equals("实验")&&tem[2].equals("实验")) {
351                     if(tem.length-4>=4&&tem.length - 4<=9) {
352                         if (Integer.parseInt(tem[3]) != tem.length - 4) {
353                             data.output.add_output(tem[0] + " : number of scores does not match");
354                             data.courses.remove(tem[0]);
355                             continue;
356                         }
357                         float tem_weight = 0;
358                         for (int j = 4; j < tem.length; j++) {
359                             tem_weight += Float.parseFloat(tem[j]);
360                         }
361                         if (Math.abs(tem_weight - 1) > 0.0001) {
362                             data.output.add_output(tem[0] + " : weight value error");
363                             data.courses.remove(tem[0]);
364                             continue;
365                         }
366                     }else{
367                         try {
368                             if (Integer.parseInt(tem[3]) != tem.length - 4) {
369                                 data.output.add_output(tem[0] + " : number of scores does not match");
370                                 data.courses.remove(tem[0]);
371                                 continue;
372                             }
373                         } catch (Exception ignored) {
374 
375                         }
376                     }
377                 }if((tem[1].equals("必修")||tem[1].equals("选修"))&&tem[2].equals("考试")){
378                     if(tem.length-3==2) {
379                         float tem_weight = Float.parseFloat(tem[3]) + Float.parseFloat(tem[4]);
380                         if (Math.abs(tem_weight - 1) > 0.0001) {
381                             data.output.add_output(tem[0] + " : weight value error");
382                             data.courses.remove(tem[0]);
383                         }
384                     }
385                 }
386             }else if(i.matches(regex_CS)||i.matches(regex_lab)) {
387                 if(!data.courses.containsKey(tem[2])){//不存在
388                     data.output.add_output(tem[2]+" does not exist");
389                     data.stu__st_cour.get(tem[0]).gradeMap.remove(tem[2]);
390                 }else{
391                     if(data.courses.get(tem[2]).type.equals("必修") && tem.length!=5) {//必修 但是只有期末成绩
392                         data.output.add_output(tem[0]+" "+tem[1]+" : access mode mismatch");
393                     }else if(data.courses.get(tem[2]).type.equals("选修")) {
394                         if ((data.courses.get(tem[2]).test_way.equals("考试") && tem.length != 5) ||
395                                 (data.courses.get(tem[2]).test_way.equals("考察") && tem.length != 4))
396                             data.output.add_output(tem[0] + " " + tem[1] + " : access mode mismatch");
397                     }else if(data.courses.get(tem[2]).type.equals("实验")){
398                         if(data.courses.get(tem[2]).test_way.equals("实验")&&(tem.length-3<4||tem.length-3>9||tem.length-3!=((Lab_Course) data.courses.get(tem[2])).sub_scores_num))
399                             data.output.add_output(tem[0] + " " + tem[1] + " : access mode mismatch");
400                     }
401                 }
402             }else if(!i.equals("end")){
403                 data.output.add_output("wrong format");
404             }
405         }
406         data.classes.forEach((cla_num,Class1)->{//遍历所有班级
407             Class1.students.forEach((stu_num,student)->{
408                 int tem=calculate.stu_all_grades(data,stu_num);
409                 if(tem>=0)
410                     data.output.add_output(stu_num+" "+Class1.students.get(stu_num).name+" "+tem);
411                 else
412                     data.output.add_output(stu_num+" "+Class1.students.get(stu_num).name+" "+"did not take any exams");
413             });
414         });
415         data.courses.forEach((key,value)-> {
416             int[] tem = calculate.single_course_grades(data, key);
417             if (tem[0] < 0 && tem[1] < 0 && tem[2] < 0) {//三个为- 则没成绩
418                 data.output.add_output(key + " has no grades yet");
419             }else {
420                 if (value.type.equals("选修") || value.type.equals("必修") || value.type.equals("实验")) {
421                     data.output.add_output(key + " " + tem[2]);
422                 }
423             }
424         });
425         data.classes.forEach((num,Class)->{
426             int tem = calculate.Class_grades(data,num);
427             if(tem>=0) {
428                 data.output.add_output(num + " " + tem);
429             }else
430                 data.output.add_output(num+" has no grades yet");
431         });
432     }
433     void output_all(Data_storage data){
434         data.output.output.forEach(System.out::println);
435     }
436 }
437 abstract class Score {
438     String total_scores = "-100";
439 }
440 class Student {
441     String name;
442     String num;
443     Student(String name, String num) {
444         this.name = name;
445         this.num = num;
446     }
447 }
448 class StudentsAll_mes {
449     String num;//学生
450     TreeMap<String,Score> gradeMap =new TreeMap<>();
451     StudentsAll_mes(String stu_name, String course, String normal_score,String test_score){
452         this.num = stu_name;
453         gradeMap.put(course,new Test_Score(normal_score,test_score));
454     }
455     StudentsAll_mes(String stu_name, String course, String test_score){
456         this.num = stu_name;
457         gradeMap.put(course,new Inspect_Score(test_score));
458     }
459 
460     public StudentsAll_mes() {
461 
462     }
463     void set_lab_stu_mes(String stu_num,String course,String lab_num,ArrayList<Integer> scores){
464         this.num = stu_num;
465         gradeMap.put(course,new Lab_Score(lab_num,scores));
466     }
467     void set_lab_gradeMap(String course,String lab_num,ArrayList<Integer> scores){
468         if(!gradeMap.containsKey(course))
469             gradeMap.put(course,new Lab_Score(lab_num,scores));
470     }
471     void setGradeMap(String course, String normal_score,String test_score){
472         if(!gradeMap.containsKey(course))
473             gradeMap.put(course, new Test_Score(normal_score,test_score));
474     }
475     void setGradeMap(String course,String test_score){
476         if(!gradeMap.containsKey(course))
477             gradeMap.put(course,new Inspect_Score(test_score));
478     }
479 }
480 class Test_Score extends Score{
481     String normal_score;
482     String end_score;
483     Test_Score(String normal_score,String end_score) {
484         this.normal_score = normal_score;
485         this.end_score = end_score;
486     }
487 }
488 class Lab_Score extends Score {
489     String lab_num;//试验次数
490     ArrayList<Integer> scores;
491     Lab_Score(String lab_num,ArrayList<Integer> scores){
492         this.lab_num = lab_num;
493         this.scores = scores;
494     }
495 }
496 class InAndOut_put {
497     List<String> output = new ArrayList<>();
498     List<String> input = new ArrayList<>();
499     void add_output(String out){
500         output.add(out);
501     }
502     void add_input(String out){
503         input.add(out);
504     }
505 }
课程成绩统计程序-3

  

我的代码中的主要类和功能如下:

  • Main类:包含程序的入口方法main,用于接收用户输入、处理数据和输出结果。
  • Data_storage类:用于存储数据,包括课程、班级和学生的信息,以及学生的成绩。
  • Input_Format类:用于处理用户输入的数据,并根据输入的格式解析和存储相关信息。
  • Output_Format类:用于对数据进行计算和格式化输出,包括计算学生平均成绩、课程平均成绩和班级平均成绩等。
  • Calculate_grades类:用于计算学生、课程和班级的平均成绩。
  • Class类:表示一个班级,包含班级号和学生信息。
  • Course类及其子类:表示一个课程,包含课程名称、类型和考试方式等信息。
  • Score类及其子类:表示学生的成绩,包括平时成绩、期末考试成绩和总分成绩等。
代码通过读取用户输入的数据,解析并存储到相应的数据结构中。然后根据存储的数据进行成绩计算和格式化输出。其中,成绩计算部分涉及单个学生总课程平均分计算、单门课程成绩计算和班级平均成绩计算。
主要类图如下:

  从类图可以看出本次代码非常复杂,我彻底改变了课程程序统计程序-2的逻辑结构,改变了原来的输入输出读取方式以及字符匹配模式。

本次代码的圈复杂度如下:

   从这个图可以看出,本次代码虽然类很多,但是结构比第二次作业要清晰,代码深度较高,平均的复杂度以及选择分支减少,减少了内存开销。

期末考试

7-1 立体图形问题
分数 10
作者 段喜龙
单位 南昌航空大学

编程求得正方体和正三棱锥的表面积和体积,要求必须体现扩展性(继承)和多态性。

类结构如下图所示(参考):

image.png
试编程完成如上类设计,主方法源码如下(可直接拷贝使用):

 
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Scanner input = new Scanner(System.in);
    double side = input.nextDouble();
        
    display(new Cube(side));
    display(new RegularPyramid(side));
}

其中,display(Solid solid)方法为定义在Main类中的静态方法,作用为体现程序的多态性。

注:正三棱锥的体积计算公式为底面积*高/3。

输入格式:

输入一个实型数,分别作为正方体的边长和正三棱锥的边长。

输出格式:

分别输出正方体的表面积、体积以及正棱锥的表面积和体积。保留两位小数,建议使用String.format(“%.2f”,value)

进行小数位数控制。


输入样例:

在这里给出一组输入。例如:

2.5

输出样例:

在这里给出相应的输出。例如:

37.50
15.63
10.83
1.84
这个题目难度不大,主要在于三棱锥的体积与表面积的计算方法以及截断整数那里让我修改了一次。
我的代码如下:
import java.util.Scanner;

abstract class Solid {
    protected double side;

    public Solid(double side) {
        this.side = side;
    }

    public abstract double getSurfaceArea();

    public abstract double getVolume();
}

class Cube extends Solid {
    public Cube(double side) {
        super(side);
    }

    public double getSurfaceArea() {
        return 6 * Math.pow(side, 2);
    }

    public double getVolume() {
        return Math.pow(side, 3);
    }
}

class RegularPyramid extends Solid {
    public RegularPyramid(double side) {
        super(side);
    }

    public double getSurfaceArea() {
        return Math.pow(side, 2) *Math.sqrt(3);
    }

    public double getVolume() {
        return Math.pow(side, 3) / (6 * Math.sqrt(2));
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        double side = input.nextDouble();

        display(new Cube(side));
        display(new RegularPyramid(side));
    }

    public static void display(Solid solid) {
        System.out.println(String.format("%.2f", solid.getSurfaceArea()));
        System.out.println(String.format("%.2f", solid.getVolume()));
    }
}

  

  • Solid是一个抽象类,表示几何体,包含一个受保护的成员变量side表示边长,以及两个抽象方法getSurfaceArea()getVolume()用于计算几何体的表面积和体积。
  • CubeSolid的子类,表示立方体,通过继承Solid类并实现抽象方法来计算立方体的表面积和体积。
  • RegularPyramid也是Solid的子类,表示正四面体,同样通过继承Solid类并实现抽象方法来计算正四面体的表面积和体积。
  • Main类包含了程序的入口方法main,在该方法中使用Scanner类获取用户输入的边长,然后创建一个立方体和一个正四面体对象,并调用display方法显示它们的表面积和体积。
  • display方法接受一个Solid类型的参数,根据传入的具体几何体对象调用相应的方法来显示它们的表面积和体积。
本次代码的行数以及结构很清晰明了,在此不贴出其类图及复杂度分析。

问题描述:本问题中的魔方有两种,一种是正方体魔方,一种是正三棱锥魔方,其中,正方体或正三棱锥魔方是由单元正方体或正三棱锥组成,单元正方体或正三棱锥的个数由阶数(即层数)决定,即魔方边长=阶数*单元边长。魔方如下图所示:


image.png

 

利用“立体图形”问题源码,实现如下功能:


魔方有三个属性:颜色,阶数,类型(正方体魔方、正三棱锥魔方),程序要求输出魔方的颜色、表面积和体积。参考设计类图如下所示:


image.png


主方法部分可参考如下源码(可拷贝直接使用):



 

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner input = new Scanner(System.in);
        
        String color = input.next();
        int layer = input.nextInt();
        double side = input.nextDouble();        
        
        RubikCube cube1 = new SquareCube(color, layer,new Cube(side)); 
                
        color = input.next();
        layer = input.nextInt();
        side = input.nextDouble();
        
        RubikCube cube2 = new RegularPyramidCube(color, layer,new RegularPyramid(side));
        display(cube1);
        display(cube2);
    }
}

其中,display(RubikCube cube)方法为Main类中定义的静态方法,用户输出魔方的信息,用于体现多态性。


输入格式:


第一部分:正方体魔方颜色、阶数、单元正方体边长,以空格或回车分隔;


第二部分:正三棱锥魔方颜色、阶数、单元正三棱锥边长,以空格或回车分隔。


输出格式:


正方体魔方颜色


正方体魔方表面积


正方体魔方体积


正三棱锥魔方颜色


正三棱锥魔方表面积
正三棱锥魔方体积


注:小数点保留两位


输入样例:


在这里给出一组输入。例如:


red 3 4.5
black 4 2.1

输出样例:


在这里给出相应的输出。例如:


red
1093.50
2460.38
black
122.21
69.85
这道题目只需要在第一道的基础上略微修改计算方式以及添加抽象魔方类即可解决。
代码如下:
import java.util.Scanner;

abstract class Solid {
    protected double side;

    public Solid(double side) {
        this.side = side;
    }

    public abstract double getSurfaceArea();

    public abstract double getVolume();
}

class Cube extends Solid {
    public Cube(double side) {
        super(side);
    }

    public double getSurfaceArea() {
        return 6 * Math.pow(side, 2);
    }

    public double getVolume() {
        return Math.pow(side, 3);
    }
}

class RegularPyramid extends Solid {
    public RegularPyramid(double side) {
        super(side);
    }

    public double getSurfaceArea() {
        return Math.pow(side, 2) *Math.sqrt(3);
    }

    public double getVolume() {
        return Math.pow(side, 3) / (6 * Math.sqrt(2));
    }
}

abstract class RubikCube {
    protected String color;
    protected int layer;
    protected 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 abstract double getSurfaceArea();

    public abstract double getVolume();
}

class SquareCube extends RubikCube {
    public SquareCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    public double getSurfaceArea() {
        return 6 * Math.pow(layer * solid.side, 2);
    }

    public double getVolume() {
        return Math.pow(layer * solid.side, 3);
    }
}

class RegularPyramidCube extends RubikCube {
    public RegularPyramidCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    public double getSurfaceArea() {
        return layer * layer * solid.getSurfaceArea();
    }

    public double getVolume() {
        return layer * layer * layer * solid.getVolume();
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        String color = input.next();
        int layer = input.nextInt();
        double side = input.nextDouble();

        RubikCube cube1 = new SquareCube(color, layer, new Cube(side));

        color = input.next();
        layer = input.nextInt();
        side = input.nextDouble();

        RubikCube cube2 = new RegularPyramidCube(color, layer, new RegularPyramid(side));
        display(cube1);
        display(cube2);
    }

    public static void display(RubikCube cube) {
        System.out.println(cube.getColor());
        System.out.println(String.format("%.2f", cube.getSurfaceArea()));
        System.out.println(String.format("%.2f", cube.getVolume()));
    }
}
View Code

  • RubikCube是一个抽象类,表示魔方,包含颜色、层数和几何体对象的信息。它继承自Solid类,并实现了抽象方法getSurfaceArea()getVolume()来计算魔方的表面积和体积。
  • SquareCubeRubikCube的子类,表示正方体魔方。通过继承RubikCube类并实现抽象方法来计算正方体魔方的表面积和体积。
  • RegularPyramidCube也是RubikCube的子类,表示正四面体魔方。同样通过继承RubikCube类并实现抽象方法来计算正四面体魔方的表面积和体积。

Main类中,除了之前的功能外,添加了用户输入魔方的颜色、层数和边长。根据用户输入创建一个正方体魔方对象和一个正四面体魔方对象,并调用display方法显示它们的颜色、表面积和体积。

display方法接受一个RubikCube类型的参数,根据传入的魔方对象调用相应的方法来显示它们的颜色、表面积和体积。


7-3 魔方排序问题
分数 20

作者 段喜龙
单位 南昌航空大学

在魔方问题的基础上,重构类设计,实现列表内魔方的排序功能(按照魔方的体积进行排序)。

提示:题目中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
这道题目是在魔方问题的基础上,对用户输入的魔方数据的表面和体积进行排序。
我的代码如下:
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Comparator;
abstract class Solid {
    protected double side;

    public Solid(double side) {
        this.side = side;
    }

    public abstract double getSurfaceArea();

    public abstract double getVolume();
}

class Cube extends Solid {
    public Cube(double side) {
        super(side);
    }

    public double getSurfaceArea() {
        return 6 * Math.pow(side, 2);
    }

    public double getVolume() {
        return Math.pow(side, 3);
    }
}

class RegularPyramid extends Solid {
    public RegularPyramid(double side) {
        super(side);
    }

    public double getSurfaceArea() {
        return Math.pow(side, 2) *Math.sqrt(3);
    }

    public double getVolume() {
        return Math.pow(side, 3) / (6 * Math.sqrt(2));
    }
}

abstract class RubikCube implements Comparable<RubikCube> {
    protected String color;
    protected int layer;
    protected 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 abstract double getSurfaceArea();

    public abstract double getVolume();

    @Override
    public int compareTo(RubikCube other) {
        return Double.compare(this.getVolume(), other.getVolume());
    }
}
class SquareCube extends RubikCube {
    public SquareCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    public double getSurfaceArea() {
        return 6 * Math.pow(layer * solid.side, 2);
    }

    public double getVolume() {
        return Math.pow(layer * solid.side, 3);
    }
}

class RegularPyramidCube extends RubikCube {
    public RegularPyramidCube(String color, int layer, Solid solid) {
        super(color, layer, solid);
    }

    public double getSurfaceArea() {
        return layer * layer * solid.getSurfaceArea();
    }

    public double getVolume() {
        return layer * layer * layer * solid.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() + " " + 
        String.format("%.2f", list.get(i).getSurfaceArea()) + " " + 
        String.format("%.2f", list.get(i).getVolume()) );
            System.out.println("");
        }            
    }    
}
View Code

这段代码中的类包括:

  • Solid:抽象基类,表示一个立体,包含边长属性和计算表面积和体积的抽象方法。
  • Cube:继承自Solid,表示一个立方体,实现了计算表面积和体积的方法。
  • RegularPyramid:继承自Solid,表示一个正四面体,实现了计算表面积和体积的方法。
  • RubikCube:抽象基类,表示一个魔方,包含颜色、层数和实际立体对象的属性,以及计算表面积和体积的抽象方法和比较方法。
  • SquareCube:继承自RubikCube,表示一个立方体魔方,实现了计算表面积和体积的方法。
  • RegularPyramidCube:继承自RubikCube,表示一个金字塔魔方,实现了计算表面积和体积的方法。
  • Main:主类,包含main方法,用于接收用户输入、创建魔方对象、进行排序和打印结果。

用户可以通过输入数字选择魔方类型(1表示立方体魔方,2表示金字塔魔方),然后依次输入颜色、层数和边长。输入0表示结束输入。

最后,程序将根据魔方的体积对魔方列表进行排序,并打印每个魔方的颜色、表面积和体积。

我的代码的类图如下:

 

在原来的魔方问题代码上,我添加了用户选择立体类型以及排序输出部分。

7-4 销售步枪问题(附加题)
分数 10

作者 段喜龙
单位 南昌航空大学

前亚利桑那州境内的一位步枪销售商销售密苏里州制造的步枪机(lock)、枪托(stock)和枪管(barrel)。枪机卖45美元,枪托卖30美元,枪管卖25美元。销售商每月至少要售出一支完整的步枪,且生产限额是销售商在一个月内可销售70个枪机、80个枪托和90个枪管。

根据每个月的销售情况,计算销售商的佣金(提成)算法如下:

  • 不到(含)1000美元的部分为10%;

  • 1000(含)~1800美元的部分为15%;

  • 超过1800美元的部分为20%。

佣金程序生成月份销售报告,汇总销售商的销售总额和佣金。

编程要求:必须符合面向对象编程,且保证类设计的单一职责模式,使用面向过程编程判定0分。

提示:可以设置一个销售订单类。参考类图如下:

image.png

输入格式:

输入销售商每个月售出枪机、枪托、枪管的数量,可以用空格或者回车分隔。

输出格式:

分别输出销售商在该月的销售额和佣金,中间用空格分开。

输入样例1:

在这里给出一组输入。例如:

30 40 50

输出样例1:

在这里给出相应的输出。例如:

3800.00 620.00

输入样例2:
在这里给出一组输入。例如:

88 56 98

输出样例2:
在这里给出相应的输出。例如:

Wrong Format

这是一道简单的题目,我的代码如下:

import java.util.Scanner;

class SalesOrder {
    private int lockCount;
    private int stockCount;
    private int barrelCount;

    private static final int LOCK_PRICE = 45;
    private static final int STOCK_PRICE = 30;
    private static final int BARREL_PRICE = 25;

    public SalesOrder(int lockCount, int stockCount, int barrelCount) {
        if ((lockCount > 70 || stockCount > 80 || barrelCount > 90)||(lockCount<1||stockCount<1||barrelCount<1)) {
            throw new IllegalArgumentException("Wrong Format");
        }
        this.lockCount = lockCount;
        this.stockCount = stockCount;
        this.barrelCount = barrelCount;
    }

    public double calculateTotalSales() {
        return lockCount * LOCK_PRICE + stockCount * STOCK_PRICE + barrelCount * BARREL_PRICE;
    }

    public double calculateCommission() {
        double totalSales = calculateTotalSales();
        if (totalSales <= 1000) {
            return totalSales * 0.10;
        } else if (totalSales <= 1800) {
            return 1000 * 0.10 + (totalSales - 1000) * 0.15;
        } else {
            return 1000 * 0.10 + 800 * 0.15 + (totalSales - 1800) * 0.20;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        int lockCount = input.nextInt();
        int stockCount = input.nextInt();
        int barrelCount = input.nextInt();

        try {
            SalesOrder order = new SalesOrder(lockCount, stockCount, barrelCount);
            System.out.printf("%.2f %.2f\n", order.calculateTotalSales(), order.calculateCommission());
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

这是期末考试的附加题,难度不大,只要注意题目的条件控制好输入输出,基本不会出错。

总结:

  这阶段的题目是PTA的最后一部分题目,题目难度相较于第二次也变小了,最后一阶段的题目加入了很多面向对象java的特点题目,加入了接口,继承多态部分题目,这些题目让我对面向对象java这门语言更加熟悉和了解,PTA的题目让我记忆犹新,我曾因为两道题做出来而窃窃自喜,也曾因为菜单计价系列题目而痛不欲生,这些都使我受益良多,最后一阶段的题目算是对java的学习到了一个新阶段,我开始有意识地理清代码结构以及想办法降低代码复杂度,而不是像以前一样只求做出来,我开始思考题目的需求和哪些方法匹配,字符匹配是否需要用到正则表达式,类的设计是应该继承还是组合,应该用哪种方式来储存数据(链表还是数组)……,这些思考使我的代码能力和设计思维进一步提高,为我以后的工作和学习打下了良好的基础。