前言
本次博客涵盖了Java题目的主要知识点,包括以下内容:
面向对象的基础知识:介绍了类和对象的基本概念、构造方法、访问权限和成员变量。
面向对象的设计原则:重点讲解了继承和组合这两个重要的设计原则。要求学生对这两种原则有深入的理解,并能根据实际需求选择合适的设计方式。
异常处理:涉及了大量的异常情况,要求学生能正确地处理这些异常。详细说明了异常处理的方法和技巧。
字符串处理:涉及到输入和输出格式的字符串处理,包括拆分、组合和转换等操作。
基础的控制流和数据结构:包括循环、条件语句、数组和列表等基本的控制流程和数据结构。
题目的难度适中偏上,旨在考察学生对面向对象设计原则和异常处理的理解程度。
题量适中,包含了许多细节和特殊情况的要求,需要对各种异常处理和特殊情况进行正确处理。
主要介绍了题集7中的成绩-2和题集8中的成绩3的题目。。
一、题集7
7-3 课程成绩统计程序-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)若出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
信息约束:
- 成绩平均分只取整数部分,小数部分丢弃。
类设计:
Course类:
Course类表示一个课程对象,具有以下属性:
course_id:课程编号
course_name:课程名称
Course类具有以下方法:
__init__:初始化方法,用于设置课程编号和课程名称
get_course_id:获取课程编号
get_course_name:获取课程名称
Student类:
Student类表示一个学生对象,具有以下属性:
student_id:学生学号
student_name:学生姓名
courses:学生选修的课程列表
Student类具有以下方法:
__init__:初始化方法,用于设置学生学号和学生姓名
add_course:添加学生选修的课程
remove_course:移除学生选修的课程
get_student_id:获取学生学号
get_student_name:获取学生姓名
get_courses:获取学生选修的课程列表
首先是Course(课程)类。这个类代表了一个课程,每个课程有一个课程编号(course_id)和一个课程名称(course_name)。我们可以把它看作是一个课程的模板。对于一个课程对象,我们可以获取它的课程编号和课程名称。 然后是Student(学生)类。这个类代表了一个学生,每个学生有一个学生学号(student_id)和一个学生姓名(student_name),还有一个选修课程的列表(courses)。我们可以把它看作是一个学生的模板。对于一个学生对象,我们可以添加或移除他选修的课程,获取他的学生学号、学生姓名以及选修课程的列表。 这些类的设计充分运用了面向对象的思想,通过定义类和对象来模拟现实世界中的实体和其行为。这样做可以使代码更加清晰、可维护,并且提供了封装和抽象的好处 |
类图:
收获和改进
在编写这段代码的过程中,我学会了如何设计类和对象,并定义它们的属性和方法。我深入了解了面向对象编程的思想,以及如何将复杂的问题拆分为简单的组件,并使代码更加模块化和可维护。
我意识到了数据验证的重要性,尤其是在处理用户输入时。为了确保输入的有效性,我学会了如何进行数据验证,并使用异常处理来捕获和处理错误情况,以保证程序的稳定性。
另外,我也学会了如何利用模块化和代码重用的概念来提高代码的可复用性和灵活性。通过将相关功能封装成函数或类方法,我可以在不同的程序中重复使用它们,节省时间和精力。
同时,我也注意到了良好的文档注释和清晰的命名对于代码的可读性和可维护性的重要性。通过添加详细的注释和使用具有描述性的命名,我可以更轻松地理解和修改代码,也方便其他人阅读和使用我的代码。
总的来说,通过编写这段代码,我不仅提高了我的java编程技能,还掌握了面向对象编程的基本原则。这些知识和经验对我的未来编程学习和实践将非常有帮助。
改进点:
增加更多的属性和方法:
对于Course类,可以考虑添加更多有关课程的属性,例如课程学分、授课教师等。同时,可以添加方法用于获取和设置这些属性的值。
对于Student类,可以考虑添加更多有关学生的属性,例如学生年级、专业等。同样,可以添加方法用于获取和设置这些属性的值。
引入数据验证和异常处理:
在Course和Student类的方法中,可以对输入的数据进行验证,确保数据的有效性。例如,在添加课程的方法中,可以检查课程是否已经存在,避免重复添加。
在处理可能出现错误的情况时,可以使用异常处理机制,及时捕获并处理异常,以避免程序崩溃或不可预测的行为。
添加更多实用的功能:
可以在Student类中添加方法,用于计算学生的平均成绩、最高成绩或其他相关统计信息。
可以在Course类中添加方法,用于获取当前选修某门课程的学生列表。
模块化代码重用:
可以将Course和Student类分别定义在独立的模块中,以便在其他程序中重用。
可以将一些常用的功能封装成函数或类方法,提高代码的可复用性。例如,可以编写一个函数,根据学生的成绩判断其等级(优、良、及格等)。
代码如下:
import java.util.*; public class Main { public static class Course { public static Map<String, Map<String, int[]>> classScores = new HashMap<>(); public static String[] courseTypes = {"考试", "考察", "实验"}; public static Map<String, Integer> typeToCourse = new HashMap<>(); static { typeToCourse.put("考试", 0); typeToCourse.put("考察", 1); typeToCourse.put("实验", 2); } private String name; private int courseType; private int score; private int examScore; private int num; public Course(String name, int type) { this.name = name; this.courseType = type; score = examScore = num = 0; } public int getAvgScore() { return score / num; } public int getAvgExamScore() { return examScore / num; } public int getTotalAvgScore() { if (courseType == 0) { return (int)(((int)(score * 0.3) + (int)(examScore * 0.7)) / num); } else { return score / num; } } public void addStudent(Student student) { if(student.getScore() == -1) { String cno = student.getSno().substring(0, 6); if(!classScores.containsKey(cno)) { classScores.put(cno, new HashMap<>()); } Map<String, int[]> classScore = classScores.get(cno); if(!classScore.containsKey(name)) { classScore.put(name, new int[]{0, 0}); } return; } num ++; score += student.getScore(); examScore += student.getExamScore(); String cno = student.getSno().substring(0, 6); if(!classScores.containsKey(cno)) { classScores.put(cno, new HashMap<>()); } Map<String, int[]> classScore = classScores.get(cno); if(!classScore.containsKey(name)) { classScore.put(name, new int[]{0, 0}); } int[] totalScore = classScore.get(name); totalScore[0] += student.getTotalScore(); totalScore[1] += 1; } public static void printClass(String name, Map<String, int[]> classScore) { int ans = 0, num = 0; for (int[] totalScore: classScore.values()) { if(totalScore[1] == 0) continue; ans += totalScore[0]; num += totalScore[1]; } if(num == 0) { System.out.println(name + " has no grades yet"); return ; } ans /= num; System.out.println(name + " " + ans); } public static void printScore() { List<String> names = new ArrayList<>(classScores.keySet()); Collections.sort(names); for (String name : names) { printClass(name, classScores.get(name)); } } public static void setCourseTypes(String[] courseTypes) { Course.courseTypes = courseTypes; } public static Map<String, Integer> getTypeToCourse() { return typeToCourse; } public static void setTypeToCourse(Map<String, Integer> typeToCourse) { Course.typeToCourse = typeToCourse; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCourseType() { return courseType; } public int getScore() { return score; } public int getNum() { return num; } } public static class Student implements Comparator<Student>{ private String sno; private String name; private int courseType; private int score; private int examScore; private int totalScore; private int num; @Override public int compare(Student o1, Student o2) { return o1.getSno().compareTo(o2.getSno()); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return Objects.equals(sno, student.sno); } public Student(String sno, String name, int type, int score) { this.sno = sno; this.name = name; this.courseType = type; this.score = score; this.totalScore = getTotalScore(); num = 1; if(score == -1) num = 0; } public Student(String sno, String name, int type, int score, int examScore) { this.sno = sno; this.name = name; this.courseType = type; this.score = score; this.examScore = examScore; this.totalScore = getTotalScore(); num = 1; } public void addSelf(Student student) { if(student.getScore() == -1) { return; } num ++; totalScore += student.getTotalScore(); } public String getSno() { return sno; } public String getName() { return name; } public int getCourseType() { return courseType; } public int getScore() { return score; } public int getExamScore() { return examScore; } public int getAvgScore() { return score; } public int getAvgExamScore() { return examScore; } public int getTotalScore() { if (courseType == 0) { return (int)(((score * 0.3) + (examScore * 0.7))); } else { return score; } } public int getTotalAvgScore() { return totalScore / num; } public Student() { } public int getNum() { return num; } public void setCourseType(int courseType) { this.courseType = courseType; } } public static boolean isNum(String s) { for(int i = 0; i < s.length(); i ++ ) { if(s.charAt(i) > '9' || s.charAt(i) < '0') { return false; } } return true; } public static boolean check(String[] ss) { if(!isNum(ss[0]) || !isNum(ss[3])) { System.out.println("wrong format"); return false; } int x = Integer.parseInt(ss[3]); if(x > 100 || x < 0) { System.out.println("wrong format"); return false; } if (ss.length == 4) { return true; } else if(ss.length == 5) { int examScore = Integer.parseInt(ss[4]); if(examScore > 100 || examScore < 0) { System.out.println("wrong format"); return false; } return true; } else if(ss.length <= 3) { System.out.println("wrong format"); return false; } else { if(x + 4 == ss.length) { for (int i = 0; i < x; i ++ ) { Integer score = Integer.parseInt(ss[i + 4]); if(score > 100 || score < 0) { System.out.println("wrong format"); return false; } } return true; } else { if(x + 4 > ss.length) return true; System.out.println("wrong format"); return false; } } } public static void main(String[] args) { Scanner in = new Scanner(System.in); String s = null; Map<String, Course> courseNameMap = new HashMap<>(); List<Student> students = new ArrayList<>(); while(!(s = in.nextLine()).equals("end")) { String[] ss = s.split(" "); if(ss.length == 3) { String courseName = ss[0]; String type = ss[1]; String examType = ss[2]; if(courseNameMap.containsKey(courseName)) { continue; } int typeNum = -1; if(type.equals("必修")) { if (examType.equals("考试")) { typeNum = 0; } } else if(type.equals("选修")) { if (examType.equals("考试")) { typeNum = 0; } else if(examType.equals("考察")) { typeNum = 1; } } else if(type.equals("实验")) { if(examType.equals("实验")) { typeNum = 2; } } if (typeNum == -1) { System.out.println(courseName + " : course type & access mode mismatch"); continue; } Course course = new Course(courseName, typeNum); courseNameMap.put(courseName, course); } else { if(!check(ss)) { continue; } // if(!check(ss)) { // System.out.println("wrong format"); // continue; // } String sno = ss[0]; String studentName = ss[1]; String courseName = ss[2]; Course course = courseNameMap.get(courseName); if(course == null) { System.out.println(sno + " "+ studentName + " :"+ courseName + " does not exist"); continue; } boolean ok = true; Student student = null; if(course.getCourseType() == 0) { if(ss.length == 5) { int score = Integer.parseInt(ss[3]); int examScore = Integer.parseInt(ss[4]); if(examScore > 100 || examScore < 0 || score > 100 || score < 0) { System.out.println("wrong format"); continue; } student = new Student(sno, studentName, course.getCourseType(), score, examScore); if(students.contains(student)) { Student tstudent = students.get(students.indexOf(student)); tstudent.setCourseType(course.getCourseType()); tstudent.addSelf(student); student = tstudent; } else { students.add(student); } course.addStudent(student); } else { ok = false; } } else if(course.getCourseType() == 1) { if(ss.length == 4) { int score = Integer.parseInt(ss[3]); if(score > 100 || score < 0) { System.out.println("wrong format"); continue; } student = new Student(sno, studentName, course.getCourseType(), score); if(students.contains(student)) { Student tstudent = students.get(students.indexOf(student)); tstudent.setCourseType(course.getCourseType()); tstudent.addSelf(student); student = tstudent; } else { students.add(student); } course.addStudent(student); } else { ok = false; } } else if(course.getCourseType() == 2) { if(ss.length == 2) { ok = false; } else { int x = Integer.parseInt(ss[3]); if(ss.length == x + 4) { int totalScore = 0; if(x > 9 || x < 4) { // System.out.println("wrong format"); ok = false; continue; } boolean fg = true; for(int i = 0; i < x; i ++ ) { int score = Integer.parseInt(ss[i + 4]); if(score > 100 || score < 0) { fg = false; continue; } totalScore += score; } if(!fg) { System.out.println("wrong format"); continue; } int score = totalScore / x; student = new Student(sno, studentName, course.getCourseType(), score); if(students.contains(student)) { Student tstudent = students.get(students.indexOf(student)); tstudent.setCourseType(course.getCourseType()); tstudent.addSelf(student); student = tstudent; } else { students.add(student); } course.addStudent(student); } else { ok = false; } } } if(!ok) { System.out.println(sno + " " + studentName + " : access mode mismatch"); student = new Student(sno, studentName, course.getCourseType(), -1); if(!students.contains(student)) { students.add(student); } course.addStudent(student); } } } students.sort(new Student()); for (Student student : students) { if(student.getNum() == 0) { System.out.println(student.getSno() + " " + student.getName() + " did not take any exams"); continue; } System.out.println(student.getSno() + " " + student.getName() + " " + student.getTotalAvgScore()); } List<Course> c = new ArrayList<>(); for (String key : courseNameMap.keySet()) { Course course = courseNameMap.get(key); c.add(course); } c.sort(new Comparator<Course>() { @Override public int compare(Course o1, Course o2) { return o1.getName().compareTo(o2.getName()); } }); for(Course course: c) { if(course.getNum() == 0) { System.out.println(course.getName() + " " + "has no grades yet"); continue; } String rs = course.getName() + " "; if(course.getCourseType() == 0) { rs += course.getAvgScore() + " " + course.getAvgExamScore() + " " + course.getTotalAvgScore(); } else if(course.getCourseType() == 1) { rs += course.getAvgScore() + " " + course.getAvgScore(); } else { rs += course.getAvgScore(); } System.out.println(rs); } Course.printScore(); } |
题集其他题目比较简单,在这里就不再赘述。主要是哈希函数问题和哈希表的理解。
7-1 容器-HashMap-检索 | 7-2 容器-HashMap-排序 |
import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class Main { public static void main(String[] args) { Map<String, String[]> studentMap = new HashMap<>(); Scanner scanner = new Scanner(System.in); // 输入学生信息 while (true) { String input = scanner.nextLine(); if (input.equals("end")) { break; } String[] info = input.split(" "); if (info.length >= 3) { String id = info[0]; String name = info[1]; String score = info[2]; studentMap.put(id, new String[]{name, score}); } else { System.out.println("Invalid input: " + input); } } // 查询学生信息 String queryId = scanner.nextLine(); if (studentMap.containsKey(queryId)) { String[] info = studentMap.get(queryId); System.out.println(queryId + " " + info[0] + " " + info[1]); } else { System.out.println("The student " + queryId + " does not exist"); } } } | import java.util.*; public class Main { public static void main(String[] args) { Map<String, Student> studentMap = new HashMap<>(); Scanner scanner = new Scanner(System.in); // 输入学生信息 while (scanner.hasNextLine()) { String input = scanner.nextLine(); if ("end".equals(input)) { break; } String[] info = input.split(" "); if (info.length != 3) { System.out.println("Invalid input: " + input); continue; } else if (!isNumeric(info[2])) { System.out.println("Invalid score: " + info[2]); continue; } String id = info[0]; String name = info[1]; int score = Integer.parseInt(info[2]); studentMap.put(id, new Student(name, score)); } // 按学号从大到小的顺序输出所有学生信息 List<String> idList = new ArrayList<>(studentMap.keySet()); idList.sort(Comparator.reverseOrder()); for (String id : idList) { Student student = studentMap.get(id); System.out.println(id + " " + student.getName() + " " + student.getScore()); } } private static boolean isNumeric(String str) { for (int i = 0; i < str.length(); i++) { if (!Character.isDigit(str.charAt(i))) { return false; } } return true; } } class Student { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } public String getName() { return name; } public int getScore() { return score; } } |
题集8
7-4 jmu-Java-04面向对象进阶-03-接口-自定义接口ArrayIntegerStack
定义IntegerStack接口,用于声明一个存放Integer元素的栈的常见方法:
public Integer push(Integer item);//如果item为null,则不入栈直接返回null。如果栈满,也返回null。如果插入成功,返回item。public Integer pop(); //出栈,如果为空,则返回null。出栈时只移动栈顶指针,相应位置不置为nullpublic Integer peek(); //获得栈顶元素,如果为空,则返回null.public boolean empty(); //如果为空返回truepublic int size(); //返回栈中元素个数
定义IntegerStack的实现类ArrayIntegerStack,内部使用数组实现。创建时,可指定内部数组大小。
main方法说明
- 输入n,建立可包含n个元素的ArrayIntegerStack对象
- 输入m个值,均入栈。每次入栈均打印入栈返回结果。
- 输出栈顶元素,输出是否为空,输出size
- 使用Arrays.toString()输出内部数组中的值。
- 输入x,然后出栈x次,每次出栈均打印。
- 输出栈顶元素,输出是否为空,输出size
- 使用Arrays.toString()输出内部数组中的值。
思考
如果IntegerStack接口的实现类内部使用ArrayList来存储元素,怎么实现?测试代码需要进行什么修改?
输入样例
5
3
1 2 3
2
输出样例
1
2
3
3,false,3
[1, 2, 3, null, null]
3
2
1,false,1
[1, 2, 3, null, null]
类设计思路:
设计整数栈的类时,可以考虑以下几个要素:
类的名称:选择一个合适的类名,例如"IntegerStack"或者"IntStack",以清晰地表达类的功能和用途。
成员变量:首先需要考虑使用何种数据结构来实现整数栈。可以选择数组或链表,具体取决于需求和性能要求。如果选择数组,需要定义一个整型数组来存储栈中的元素,并考虑一个变量来记录栈顶位置。如果选择链表,需要定义一个节点类(Node),每个节点包含一个整数值和指向下一个节点的指针。
构造函数:提供一个构造函数来创建整数栈的实例。可以考虑接受参数来指定初始容量或链表的头节点。
方法:
入栈(push):定义一个方法接收一个整数作为参数,并将其添加到栈顶。如果是基于数组的实现,需要检查栈是否已满,如果已满则进行扩容操作;如果是基于链表的实现,则需要创建一个新的节点并更新栈顶指针。
出栈(pop):定义一个方法从栈顶移除一个元素,并返回其值。如果是基于数组的实现,需要检查栈是否为空,如果为空则抛出异常或返回特定值;如果是基于链表的实现,需要更新栈顶指针并释放被移除的节点。
查看栈顶元素(peek):定义一个方法返回栈顶元素的值,但不修改栈的状态。如果是基于数组的实现,则直接返回栈顶位置的元素;如果是基于链表的实现,则返回栈顶节点的值。
判空(empty):定义一个方法检查栈是否为空,如果为空则返回true,否则返回false。可以通过判断栈顶位置(对于数组实现)或栈顶指针(对于链表实现)来进行判断。
获取栈中元素个数(size):定义一个方法返回栈中元素的数量。对于数组实现,可以使用栈顶位置加1;对于链表实现,可以遍历链表并计数节点的个数。
边界处理:在设计方法时,需要考虑边界情况,例如入栈时栈已满、出栈时栈已空等。可以选择抛出异常、返回特定值或进行扩容等操作来处理这些情况。
类图
在第一开始的代码编写中,始终答案错误;在修改后达到了测试要求。
主要是将IntegerStack接口中的方法改为公共访问权限(public),这是Java编程规范的一部分。
在ArrayIntegerStack类的构造函数中使用Arrays.fill(arr, null)来将数组初始化为null,而不是在创建数组后手动遍历并赋值。
push方法中增加了对插入元素为null的判断,如果插入元素为null,则直接返回null。
pop方法中增加了对栈是否为空的判断,如果为空则直接返回null。
在pop方法中,移除栈顶元素后将其置为null,以便释放元素占用的空间。
修改了Main类中的循环写法,使用while循环替代for循环。
我掌握了以下知识点:
接口的概念和使用:我学会了如何定义接口,并在类中实现接口中定义的方法。
使用数组:我学会了如何创建和使用数组,以及数组的索引、长度和初始化操作。
栈的基本操作:我学会了栈的基本操作,包括入栈、出栈、查询栈顶元素、判断栈是否为空以及获取栈中元素个数。
遵守编程规范:我了解到编程规范的重要性,通过遵守Java编程规范中的命名、注释、缩进等规范,可以使代码更加规范、易读和易于维护。
循环语句的使用:我学会了如何使用循环语句(for循环、while循环)来遍历数组或执行重复操作。
空指针异常的处理:我学会了如何避免空指针异常,特别是在操作对象时,通过对null进行判断和处理,可以确保程序的健壮性。
通过掌握这些知识点,我可以更好地理解和编写Java代码,同时也为我打下了基础,使我能够进一步学习和应用更复杂的数据结构和算法。
7-2 课程成绩统计程序-3
课程成绩统计程序-3在第二次的基础上修改了计算总成绩的方式,
要求:修改类结构,将成绩类的继承关系改为组合关系,成绩信息由课程成绩类和分项成绩类组成,课程成绩类组合分项成绩类,分项成绩类由成绩分值和权重两个属性构成。
完成课程成绩统计程序-2、3两次程序后,比较继承和组合关系的区别。思考一下哪一种关系运用上更灵活,更能够适应变更。
题目最后的参考类图未做修改,大家根据要求自行调整,以下内容加粗字体显示的内容为本次新增的内容。
某高校课程从性质上分为:必修课、选修课、实验课,从考核方式上分为:考试、考察、实验。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。
考察的总成绩直接等于期末成绩
实验的总成绩等于课程每次实验成绩乘以权重后累加而得。
课程权重值在录入课程信息时输入。(注意:所有分项成绩的权重之和应当等于1)
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。实验课的成绩必须为实验。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式、分项成绩数量、每个分项成绩的权重。
考试课信息格式:课程名称+英文空格+课程性质+英文空格+考核方式+英文空格+平时成绩的权重+英文空格+期末成绩的权重
考察课信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
实验课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式+英文空格+分项成绩数量n+英文空格+分项成绩1的权重+英文空格+。。。+英文空格+分项成绩n的权重
实验次数至少4次,不超过9次
课程性质输入项:必修、选修、实验
考核方式输入选项:考试、考察、实验
考试/考查课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
考试/考查课程成绩信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
实验课程成绩信息包括:学号、姓名、课程名称、每次成绩{在系列-2的基础上去掉了(实验次数),实验次数要和实验课程信息中输入的分项成绩数量保持一致}
实验课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+第一次实验成绩+...+英文空格+最后一次实验成绩
以上信息的相关约束:
1)成绩是整数,不包含小数部分,成绩的取值范围是【0,100】
2)学号由8位数字组成
3)姓名不超过10个字符
4)课程名称不超过10个字符
5)不特别输入班级信息,班级号是学号的前6位。
2、输出:
输出包含三个部分,包括学生所有课程总成绩的平均分、单门课程总成绩平均分、班级所有课程总成绩平均分。
为避免四舍五入误差,
计算单个成绩时,分项成绩乘以权重后要保留小数位,计算总成绩时,累加所有分项成绩的权重分以后,再去掉小数位。
学生总成绩/整个班/课程平均分的计算方法为累加所有符合条件的单个成绩,最后除以总数。
1)学生课程总成绩平均分按学号由低到高排序输出
格式:学号+英文空格+姓名+英文空格+总成绩平均分
如果某个学生没有任何成绩信息,输出:学号+英文空格+姓名+英文空格+"did not take any exams"
2)单门课程成绩按课程名称的字符顺序输出
课程成绩输出格式:课程名称+英文空格+总成绩平均分
如果某门课程没有任何成绩信息,输出:课程名称+英文空格+"has no grades yet"
3)班级所有课程总成绩平均分按班级由低到高排序输出
格式:班级号+英文空格+总成绩平均分
如果某个班级没有任何成绩信息,输出:班级名称+英文空格+ "has no grades yet"
异常情况:
1)如果解析某个成绩信息时,课程名称不在已输入的课程列表中,输出:学号+英文空格+姓名+英文空格+":"+课程名称+英文空格+"does not exist"
2)如果解析某个成绩信息时,输入的成绩数量和课程的考核方式不匹配,输出:学号+英文空格+姓名+英文空格+": access mode mismatch"
以上两种情况如果同时出现,按第一种情况输出结果。
3)如果解析某个课程信息时,输入的课程性质和课程的考核方式不匹配,输出:课程名称+" : course type & access mode mismatch"
4)格式错误以及其他信息异常如成绩超出范围等,均按格式错误处理,输出"wrong format"
5)出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
6)如果解析实验课程信息时,输入的分项成绩数量值和分项成绩权重的个数不匹配,输出:课程名称+" : number of scores does not match"
7)如果解析考试课、实验课时,分项成绩权重值的总和不等于1,输出:课程名称+" : weight value error"
信息约束:
- 成绩平均分只取整数部分,小数部分丢弃
类设计:
在成绩2的基础上增加了GradeManagementSystem类
属性:
courses:课程列表,用于存储所有的课程对象。
方法:
addCourse:向课程列表中添加新的课程对象。
addStudentToCourse:将学生添加到指定课程中。首先根据课程名称在课程列表中找到对应的课程对象,然后调用课程对象的addStudent方法将学生添加到课程中。
getCourseAverageScore:计算指定课程的平均分。首先根据课程名称在课程列表中找到对应的课程对象,然后调用课程对象的getAverageScore方法获取平均分。
getClassAverageScore:计算班级的平均分。遍历课程列表中的所有课程对象,将每个课程的平均分累加起来,并除以课程数量得到班级的平均分。
设计GradeManagementSystem类的原因是为了实现成绩管理系统的核心功能,通过该类可以方便地添加课程、添加学生、查询课程平均分和班级平均分等操作。将这些功能集中在一个类中,可以提高代码的可读性和可维护性,并且方便其他部分调用和使用这些功能。
同时,将成绩管理系统的核心功能封装在GradeManagementSystem类中,可以有效地实现模块化设计和分工合作。不同开发人员可以负责不同的模块,通过调用GradeManagementSystem类提供的方法来完成各自的任务,简化了开发流程和协作过程。
类图:
代码如下:
import java.util.*; public class Main { public static class Course { public static Map<String, Map<String, List>> classScores = new HashMap<>(); public static String[] courseTypes = {"考试", "考察", "实验"}; public static Map<String, Integer> typeToCourse = new HashMap<>(); static { typeToCourse.put("考试", 0); typeToCourse.put("考察", 1); typeToCourse.put("实验", 2); } private String name; private int courseType; private int score; private int num; private double[] weights; public Course(String name, int type) { this.name = name; this.courseType = type; score = num = 0; } public void setScore(int score) { this.score = score; } public void setNum(int num) { this.num = num; } public double[] getWeights() { return weights; } public void setWeights(double[] weights) { this.weights = weights; } public int getAvgScore() { return (int)(score / num); } public static void addClass(String cno) { if(!classScores.containsKey(cno)) { classScores.put(cno, new HashMap<>()); } } public void addStudent(Student student) { if(student.getScore() < 0) { String cno = student.getSno().substring(0, 6); if(!classScores.containsKey(cno)) { classScores.put(cno, new HashMap<>()); } Map<String, List> classScore = classScores.get(cno); if(!classScore.containsKey(name)) { List list = new ArrayList(); list.add(new Integer(0)); list.add(new Integer(0)); classScore.put(name, list); } return; } num ++; score += (int)student.getScore(); String cno = student.getSno().substring(0, 6); if(!classScores.containsKey(cno)) { classScores.put(cno, new HashMap<>()); } Map<String, List> classScore = classScores.get(cno); if(!classScore.containsKey(name)) { List list = new ArrayList(); list.add(new Integer(0)); list.add(new Integer(0)); classScore.put(name, list); } List totalScore = classScore.get(name); totalScore.set(0, (Integer)totalScore.get(0) + (int)student.getScore()); totalScore.set(1, (Integer)totalScore.get(1) + 1); } public static void printClass(String name, Map<String, List> classScore) { int ans = 0; int num = 0; for (List totalScore: classScore.values()) { if((Integer) totalScore.get(1) == 0) continue; ans += (Integer) totalScore.get(0); num += (Integer) totalScore.get(1); } if(num == 0) { System.out.println(name + " has no grades yet"); return ; } ans /= num; System.out.println(name + " " + ans); } public static void printScore() { List<String> names = new ArrayList<>(classScores.keySet()); Collections.sort(names); for (String name : names) { printClass(name, classScores.get(name)); } } public static void setCourseTypes(String[] courseTypes) { Course.courseTypes = courseTypes; } public static Map<String, Integer> getTypeToCourse() { return typeToCourse; } public static void setTypeToCourse(Map<String, Integer> typeToCourse) { Course.typeToCourse = typeToCourse; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCourseType() { return courseType; } public double getScore() { return score; } public int getNum() { return num; } } public static class Student implements Comparator<Student>{ private String sno; private String name; private Course course; private double score; private int totalScore; private int num; @Override public int compare(Student o1, Student o2) { return o1.getSno().compareTo(o2.getSno()); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return Objects.equals(sno, student.sno); } public Student(String sno, String name, Course course, double score) { this.sno = sno; this.name = name; this.course = course; this.score = score; this.totalScore = (int)score; num = 1; if(score < 0) num = 0; } public void addSelf(Student student) { if(student.getScore() == -1) { return; } num ++; totalScore += student.getScore(); } public String getSno() { return sno; } public String getName() { return name; } public Course getCourse() { return course; } public double getScore() { return score; } public int getTotalAvgScore() { return (int)(totalScore / num); } public Student() { } public int getNum() { return num; } public void setCourse(Course course) { this.course = course; } } public static boolean isNum(String s) { for(int i = 0; i < s.length(); i ++ ) { if(s.charAt(i) > '9' || s.charAt(i) < '0') { return false; } } return true; } public static boolean check(String[] ss) { if(!isNum(ss[0]) || !isNum(ss[3])) { System.out.println("wrong format"); return false; } int x = Integer.parseInt(ss[3]); if(x > 100 || x < 0) { System.out.println("wrong format"); return false; } if (ss.length == 4) { return true; } else if(ss.length == 5) { int examScore = Integer.parseInt(ss[4]); if(examScore > 100 || examScore < 0) { System.out.println("wrong format"); return false; } return true; } else if(ss.length <= 3) { System.out.println("wrong format"); return false; } else { if(x + 4 == ss.length) { for (int i = 0; i < x; i ++ ) { Integer score = Integer.parseInt(ss[i + 4]); if(score > 100 || score < 0) { System.out.println("wrong format"); return false; } } return true; } else { if(x + 4 > ss.length) return true; System.out.println("wrong format"); return false; } } } public static void main(String[] args) { Scanner in = new Scanner(System.in); String s = null; Map<String, Course> courseNameMap = new HashMap<>(); List<Student> students = new ArrayList<>(); while(!(s = in.nextLine()).equals("end")) { String[] ss = s.split(" "); if(!isNum(ss[0])) { String courseName = ss[0]; String type = ss[1]; String examType = ss[2]; if(courseNameMap.containsKey(courseName)) { continue; } int typeNum = -1; if(type.equals("必修")) { if (examType.equals("考试")) { typeNum = 0; } } else if(type.equals("选修")) { if (examType.equals("考试")) { typeNum = 0; } else if(examType.equals("考察")) { typeNum = 1; } } else if(type.equals("实验")) { if(examType.equals("实验")) { typeNum = 2; } } if (typeNum == -1) { System.out.println(courseName + " : course type & access mode mismatch"); continue; } Course course = new Course(courseName, typeNum); if(typeNum == 1) { course.setWeights(new double[]{1.0}); } else if(typeNum == 0) { double[] weights = new double[2]; weights[0] = Double.parseDouble(ss[3]); weights[1] = Double.parseDouble(ss[4]); course.setWeights(weights); } else if(typeNum == 2) { int n = Integer.parseInt(ss[3]); if(ss.length - 4 != n) { System.out.println(course.getName() + " : number of scores does not match"); continue; } double[] weights = new double[ss.length - 4]; double sumWeight = 0; for (int i = 4; i < ss.length; i ++ ) { weights[i - 4] = Double.parseDouble(ss[i]); sumWeight += weights[i - 4]; } if(Math.abs(sumWeight - 1.0) > 1e-7) { System.out.println(course.getName() + " : weight value error"); continue; } course.setWeights(weights); } courseNameMap.put(courseName, course); } else { // if(!check(ss)) { // continue; // } String sno = ss[0]; String studentName = ss[1]; String courseName = ss[2]; Course course = courseNameMap.get(courseName); if(course == null) { System.out.println(courseName + " does not exist"); Student student = new Student(sno, studentName, course, - 1); students.add(student); Course.addClass(sno.substring(0, 6)); continue; } boolean ok = true; Student student = null; if(ss.length == 2) { ok = false; } else if(ss.length != course.weights.length + 3) { System.out.println(sno+" "+studentName+" "+": access mode mismatch"); ok = false; } else { int n = course.weights.length; if(course.getCourseType() == 2 && (n > 9 || n < 4)) { System.out.println(course.getName()+" : course type & access mode mismatch"); ok = false; continue; } else { double totalScore = 0; boolean fg = true; for(int i = 0; i < n; i ++ ) { int score = Integer.parseInt(ss[i + 3]); if(score > 100 || score < 0) { fg = false; continue; } totalScore += score * course.getWeights()[i]; } if(!fg) { System.out.println("wrong format"); continue; } double score = totalScore + 1e-7; student = new Student(sno, studentName, course, score); if(students.contains(student)) { Student tstudent = students.get(students.indexOf(student)); tstudent.setCourse(course); tstudent.addSelf(student); student = tstudent; } else { students.add(student); } course.addStudent(student); } } if(!ok) { student = new Student(sno, studentName, course, -1); if(!students.contains(student)) { students.add(student); } course.addStudent(student); } } } students.sort(new Student()); for (Student student : students) { if(student.getNum() == 0) { System.out.println(student.getSno() + " " + student.getName() + " did not take any exams"); continue; } System.out.println(student.getSno() + " " + student.getName() + " " + student.getTotalAvgScore()); } List<Course> c = new ArrayList<>(); for (String key : courseNameMap.keySet()) { Course course = courseNameMap.get(key); c.add(course); } c.sort(new Comparator<Course>() { @Override public int compare(Course o1, Course o2) { return o1.getName().compareTo(o2.getName()); } }); for(Course course: c) { if(course.getNum() == 0) { System.out.println(course.getName() + " " + "has no grades yet"); continue; } String rs = course.getName() + " " + course.getAvgScore(); System.out.println(rs); } Course.printScore(); } } |
踩坑心得
应该多给代码标上备注。比如这几次题目集相隔时间有点远,导致我对之前的代码没什么记忆,又没有注释,让我读起来还需要仔细回忆一下这些东西都是干什么的,浪费了很多时间,也感到了注释的重要性。
不要瞎写,先动脑子再动键盘,我往往是感觉哪不对就改,并没有想好怎么改,导致代码冗余。
高效debug是改代码的关键。
总结分析
我学到了很多关于代码改进的知识和技巧。我意识到了面向对象的设计和合适的数据结构对于代码的可读性和可维护性的重要性。我也学会了使用流式操作和Lambda表达式来简化代码。此外,我还学到了错误处理和异常处理的重要性,以及如何编写适当的单元测试来验证代码的正确性。
然而,我也意识到自己还有很多需要进一步学习和研究的地方。首先,我需要进一步学习和掌握更多的面向对象的设计原则和模式,以便更好地设计和实现代码。其次,我需要深入了解不同的数据结构和算法,并了解它们的优缺点,以便在实际的编程中能够选择合适的数据结构和算法。此外,我还需要进一步学习和研究关于异常处理和错误处理的最佳实践,以及如何编写更全面和有效的单元测试。
"通过这次题目集的练习,我对面向对象设计的三大原则有了更深入的理解。首先是单一职责原则,即确保每个类只负责一个清晰的职责或功能,从而使得类的设计更加简洁和清晰。比如,在课程成绩统计程序-1过渡到课程成绩统计程序-2时,只需修改Course类即可,这充分体现了单一职责原则的优势。
其次是开放封闭原则,它强调软件实体应对扩展是开放的,对修改是封闭的。也就是说,一旦实体的行为需要更改,应该通过扩展新的代码来实现,而不是修改原有的代码。这种做法能够避免对已有代码的潜在风险和影响,提高代码的稳定性。
最后是里氏替换原则,它要求子类必须能够替换其父类并保持原有行为。这种特性可以实现代码的扩展和复用,比如在课程成绩统计程序-1中,Score的两个子类ExamScore和InspectScore就充分体现了里氏替换原则的好处。
熟悉并遵循这些类的设计原则可以使代码更加灵活、可扩展和易于理解,从而提高软件的可靠性和可维护性。这些原则不仅在这个题目集中有所体现,在日常的软件开发中同样适用。"。
标签:String,int,博客,course,课程,student,public From: https://www.cnblogs.com/zhcy-99/p/17879967.html