前言
本次博客针对面向对象程序设计的课程所发的PTA作业7,8以及期末考试中的面向对象编程题的分析和总结,重点介绍课程成绩统计程序系列题目以及期末考试的编程题。
PTA第七次作业
在这次作业中7-1、7-2内容和考点相同,在此我分析一下7-2Hashmap的排序这个问题。
输入多个学生的成绩信息,包括:学号、姓名、成绩。
学号是每个学生的唯一识别号,互不相同。
姓名可能会存在重复。
要求:使用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,下面是这道题目的介绍和分析。
课程成绩统计程序-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
这个题目是课程成绩统计程序-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第八次作业
课程成绩统计程序-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
这道题目是对课程成绩统计程序-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 }
我的代码中的主要类和功能如下:
Main
类:包含程序的入口方法main
,用于接收用户输入、处理数据和输出结果。Data_storage
类:用于存储数据,包括课程、班级和学生的信息,以及学生的成绩。Input_Format
类:用于处理用户输入的数据,并根据输入的格式解析和存储相关信息。Output_Format
类:用于对数据进行计算和格式化输出,包括计算学生平均成绩、课程平均成绩和班级平均成绩等。Calculate_grades
类:用于计算学生、课程和班级的平均成绩。Class
类:表示一个班级,包含班级号和学生信息。Course
类及其子类:表示一个课程,包含课程名称、类型和考试方式等信息。Score
类及其子类:表示学生的成绩,包括平时成绩、期末考试成绩和总分成绩等。
代码通过读取用户输入的数据,解析并存储到相应的数据结构中。然后根据存储的数据进行成绩计算和格式化输出。其中,成绩计算部分涉及单个学生总课程平均分计算、单门课程成绩计算和班级平均成绩计算。
主要类图如下:
从类图可以看出本次代码非常复杂,我彻底改变了课程程序统计程序-2的逻辑结构,改变了原来的输入输出读取方式以及字符匹配模式。
本次代码的圈复杂度如下:
从这个图可以看出,本次代码虽然类很多,但是结构比第二次作业要清晰,代码深度较高,平均的复杂度以及选择分支减少,减少了内存开销。
期末考试
编程求得正方体和正三棱锥的表面积和体积,要求必须体现扩展性(继承)和多态性。
类结构如下图所示(参考):
试编程完成如上类设计,主方法源码如下(可直接拷贝使用):
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()
用于计算几何体的表面积和体积。Cube
是Solid
的子类,表示立方体,通过继承Solid
类并实现抽象方法来计算立方体的表面积和体积。RegularPyramid
也是Solid
的子类,表示正四面体,同样通过继承Solid
类并实现抽象方法来计算正四面体的表面积和体积。Main
类包含了程序的入口方法main
,在该方法中使用Scanner
类获取用户输入的边长,然后创建一个立方体和一个正四面体对象,并调用display
方法显示它们的表面积和体积。display
方法接受一个Solid
类型的参数,根据传入的具体几何体对象调用相应的方法来显示它们的表面积和体积。
本次代码的行数以及结构很清晰明了,在此不贴出其类图及复杂度分析。
问题描述:本问题中的魔方有两种,一种是正方体魔方,一种是正三棱锥魔方,其中,正方体或正三棱锥魔方是由单元正方体或正三棱锥组成,单元正方体或正三棱锥的个数由阶数(即层数)决定,即魔方边长=阶数*单元边长。魔方如下图所示:
利用“立体图形”问题源码,实现如下功能:
魔方有三个属性:颜色,阶数,类型(正方体魔方、正三棱锥魔方),程序要求输出魔方的颜色、表面积和体积。参考设计类图如下所示:
主方法部分可参考如下源码(可拷贝直接使用):
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())); } }
RubikCube
是一个抽象类,表示魔方,包含颜色、层数和几何体对象的信息。它继承自Solid
类,并实现了抽象方法getSurfaceArea()
和getVolume()
来计算魔方的表面积和体积。SquareCube
是RubikCube
的子类,表示正方体魔方。通过继承RubikCube
类并实现抽象方法来计算正方体魔方的表面积和体积。RegularPyramidCube
也是RubikCube
的子类,表示正四面体魔方。同样通过继承RubikCube
类并实现抽象方法来计算正四面体魔方的表面积和体积。
在Main
类中,除了之前的功能外,添加了用户输入魔方的颜色、层数和边长。根据用户输入创建一个正方体魔方对象和一个正四面体魔方对象,并调用display
方法显示它们的颜色、表面积和体积。
display
方法接受一个RubikCube
类型的参数,根据传入的魔方对象调用相应的方法来显示它们的颜色、表面积和体积。
在魔方问题的基础上,重构类设计,实现列表内魔方的排序功能(按照魔方的体积进行排序)。
提示:题目中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(""); } } }
这段代码中的类包括:
Solid
:抽象基类,表示一个立体,包含边长属性和计算表面积和体积的抽象方法。Cube
:继承自Solid
,表示一个立方体,实现了计算表面积和体积的方法。RegularPyramid
:继承自Solid
,表示一个正四面体,实现了计算表面积和体积的方法。RubikCube
:抽象基类,表示一个魔方,包含颜色、层数和实际立体对象的属性,以及计算表面积和体积的抽象方法和比较方法。SquareCube
:继承自RubikCube
,表示一个立方体魔方,实现了计算表面积和体积的方法。RegularPyramidCube
:继承自RubikCube
,表示一个金字塔魔方,实现了计算表面积和体积的方法。Main
:主类,包含main
方法,用于接收用户输入、创建魔方对象、进行排序和打印结果。
用户可以通过输入数字选择魔方类型(1表示立方体魔方,2表示金字塔魔方),然后依次输入颜色、层数和边长。输入0表示结束输入。
最后,程序将根据魔方的体积对魔方列表进行排序,并打印每个魔方的颜色、表面积和体积。
我的代码的类图如下:
在原来的魔方问题代码上,我添加了用户选择立体类型以及排序输出部分。
前亚利桑那州境内的一位步枪销售商销售密苏里州制造的步枪机(lock)、枪托(stock)和枪管(barrel)。枪机卖45美元,枪托卖30美元,枪管卖25美元。销售商每月至少要售出一支完整的步枪,且生产限额是销售商在一个月内可销售70个枪机、80个枪托和90个枪管。
根据每个月的销售情况,计算销售商的佣金(提成)算法如下:
-
不到(含)1000美元的部分为10%;
-
1000(含)~1800美元的部分为15%;
-
超过1800美元的部分为20%。
佣金程序生成月份销售报告,汇总销售商的销售总额和佣金。
编程要求:必须符合面向对象编程,且保证类设计的单一职责模式,使用面向过程编程判定0分。
提示:可以设置一个销售订单类。参考类图如下:
输入格式:
输入销售商每个月售出枪机、枪托、枪管的数量,可以用空格或者回车分隔。
输出格式:
分别输出销售商在该月的销售额和佣金,中间用空格分开。
输入样例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的学习到了一个新阶段,我开始有意识地理清代码结构以及想办法降低代码复杂度,而不是像以前一样只求做出来,我开始思考题目的需求和哪些方法匹配,字符匹配是否需要用到正则表达式,类的设计是应该继承还是组合,应该用哪种方式来储存数据(链表还是数组)……,这些思考使我的代码能力和设计思维进一步提高,为我以后的工作和学习打下了良好的基础。