第6-8次PTA大作业总结

一. 前言
本题目主要涉及Java编程中对输入输出、条件判断、循环、数组、字符串处理等知识点的应用。题目要求对学生的课程成绩进行统计和计算,并输出相应的平均分和排名等信息。难度适中,涵盖了多个概念和技术点。
题目如下:
某高校课程从性质上分为:必修课、选修课,从考核方式上分为:考试、考察。

考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。

考察的总成绩直接等于期末成绩

必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。

1、输入:

包括课程、课程成绩两类信息。

课程信息包括:课程名称、课程性质、考核方式(可选,如果性质是必修课,考核方式可以没有)三个数据项。

课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式

课程性质输入项:必修、选修

考核方式输入选项:考试、考察

课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩

课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩

以上信息的相关约束:

1)平时成绩和期末成绩的权重默认为0.30.7

2)成绩是整数,不包含小数部分,成绩的取值范围是【0,1003)学号由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 必修 考试
数据结构 选修 考试
形式与政治 选修 考察
end
 
输出样例1:
在这里给出相应的输出。例如:

java has no grades yet
数据结构 has no grades yet
形式与政治 has no grades yet
 
输入样例2:
单门考试课程 单个学生。例如:

java 必修 考试
20201103 张三 java 20 40
end
 
输出样例2:
在这里给出相应的输出。例如:

20201103 张三 34
java 20 40 34
202011 34
 
输入样例3:
单门考察课程 单个学生。例如:

java 选修 考察
20201103 张三 java 40
end
 
输出样例3:
在这里给出相应的输出。例如:

20201103 张三 40
java 40 40
202011 40
 
输入样例4:
考试课程 单个学生 不匹配的考核方式。例如:

java 必修 考试
20201103 张三 java 20
end
 
输出样例4:
在这里给出相应的输出。例如:

20201103 张三 : access mode mismatch
20201103 张三 did not take any exams
java has no grades yet
202011 has no grades yet
 
输入样例5:
单门课程,单个学生,课程类型与考核类型不匹配。例如:

java 必修 考察
20201103 张三 java 40
end
 
输出样例5:
在这里给出相应的输出。例如:

java : course type & access mode mismatch
java does not exist
20201103 张三 did not take any exams
202011 has no grades yet
 
输入样例6:
单门课程,多个学生。例如:

java 选修 考察
20201103 李四 java 60
20201104 王五 java 60
20201101 张三 java 40
end
 
输出样例6:
在这里给出相应的输出。例如:

20201101 张三 40
20201103 李四 60
20201104 王五 60
java 53 53
202011 53
 
输入样例7:
单门课程,单个学生,课程类型与考核类型不匹配。例如:

形式与政治 必修 考试
数据库 选修 考试
java 选修 考察
数据结构 选修 考察
20201103 李四 数据结构 70
20201103 李四 形式与政治 80 90
20201103 李四 java 60
20201103 李四 数据库 70 78
end
 
输出样例7:
在这里给出相应的输出。例如:

20201103 李四 73
java 60 60
数据结构 70 70
数据库 70 78 75
形式与政治 80 90 87
202011 73
 
输入样例8:
单门课程,单个学生,成绩越界。例如:

数据结构 选修 考察
20201103 李四 数据结构 101
end
 
输出样例8:
在这里给出相应的输出。例如:

wrong format
数据结构 has no grades yet
 
输入样例9:
多门课程,多个学生,多个成绩。例如:

形式与政治 必修 考试
数据库 选修 考试
java 选修 考察
数据结构 选修 考察
20201205 李四 数据结构 70
20201103 李四 形式与政治 80 90
20201102 王五 java 60
20201211 张三 数据库 70 78
end
 
输出样例9:
在这里给出相应的输出。例如:

20201102 王五 60
20201103 李四 87
20201205 李四 70
20201211 张三 75
java 60 60
数据结构 70 70
数据库 70 78 75
形式与政治 80 90 87
202011 73
202012 72

 

 

二. 设计与分析

源码展示:

import java.util.*;

class Course {
    private String name;
    private String nature;
    private String assessmentMethod;

    public Course(String name, String nature, String assessmentMethod) {
        this.name = name;
        this.nature = nature;
        this.assessmentMethod = assessmentMethod;
    }

    public String getName() {
        return name;
    }

    public String getNature() {
        return nature;
    }

    public String getAssessmentMethod() {
        return assessmentMethod;
    }
}

class Student {
    private String studentId;
    private String name;
    private Map<String, Integer[]> grades; // key: course name, value: [attendance, finalExam]

    public Student(String studentId, String name) {
        this.studentId = studentId;
        this.name = name;
        grades = new HashMap<>();
    }

    public String getStudentId() {
        return studentId;
    }

    public String getName() {
        return name;
    }

    public void addGrade(String courseName, Integer attendance, Integer finalExam) {
        if (grades.containsKey(courseName)) {
            return;
        }
        grades.put(courseName, new Integer[]{attendance, finalExam});
    }

    public Map<String, Integer[]> getGrades() {
        return grades;
    }

    public boolean hasGrades() {
        return !grades.isEmpty();
    }
}

class GradeAnalyzer {
    private Map<String, Course> courses;
    private Map<String, Student> students;

    public GradeAnalyzer() {
        courses = new HashMap<>();
        students = new TreeMap<>();
    }

    public void addCourse(String courseInfo) {
        String[] courseData = courseInfo.split(" ");
        if (courseData.length < 2 || courseData.length > 3) {
            System.out.println("wrong format");
            return;
        }

        String courseName = courseData[0];
        String courseNature = courseData[1];
        String assessmentMethod = courseData.length == 3 ? courseData[2] : "";

        if (courses.containsKey(courseName)) {
            return;
        }

        if (!(courseNature.equals("必修") || courseNature.equals("选修"))) {
            System.out.println(courseName + " : course type & access mode mismatch");
            return;
        }

        if (!assessmentMethod.isEmpty() && !assessmentMethod.equals("考试") && !assessmentMethod.equals("考察")) {
            System.out.println("wrong format");
            return;
        }

        Course course = new Course(courseName, courseNature, assessmentMethod);
        courses.put(courseName, course);
    }

    public void addStudentGrade(String gradeInfo) {
        String[] gradeData = gradeInfo.split(" ");
        if (gradeData.length != 6) {
            System.out.println("wrong format");
            return;
        }

        String studentId = gradeData[0];
        String name = gradeData[1];
        String courseName = gradeData[2];

        if (!courses.containsKey(courseName)) {
            System.out.println(studentId + " " + name + ": " + courseName + " does not exist");
            return;
        }

        Course course = courses.get(courseName);
        String nature = course.getNature();
        String assessmentMethod = course.getAssessmentMethod();

        if (assessmentMethod.isEmpty()) {
            System.out.println("wrong format");
            return;
        }

        int attendance, finalExam;
        try {
            attendance = Integer.parseInt(gradeData[3]);
            finalExam = Integer.parseInt(gradeData[4]);
        } catch (NumberFormatException e) {
            System.out.println("wrong format");
            return;
        }

        if (attendance < 0 || attendance > 100 || finalExam < 0 || finalExam > 100) {
            System.out.println("wrong format");
            return;
        }

        if (assessmentMethod.equals("考试")) {
            students.computeIfAbsent(studentId, id -> new Student(studentId, name))
                    .addGrade(courseName, attendance, finalExam);
        } else if (assessmentMethod.equals("考察") && nature.equals("选修")) {
            students.computeIfAbsent(studentId, id -> new Student(studentId, name))
                    .addGrade(courseName, null, finalExam);
        } else {
            System.out.println(studentId + " " + name + ": access mode mismatch");
        }
    }

    public void calculateAverages() {
        calculateStudentAverages();
        calculateCourseAverages();
        calculateClassAverages();
    }

    private void calculateStudentAverages() {
        double totalAverage = 0.0;
        int studentCount = 0;

        for (Student student : students.values()) {
            Map<String, Integer[]> grades = student.getGrades();

            if (grades.isEmpty()) {
                System.out.println(student.getStudentId() + " " + student.getName() + " did not take any exams");
                continue;
            }

            double courseTotal = 0.0;
            int courseCount = 0;

            for (Map.Entry<String, Integer[]> entry : grades.entrySet()) {
                Integer[] grade = entry.getValue();
                Integer attendance = grade[0];
                Integer finalExam = grade[1];

                if (attendance != null) {
                    double totalScore = attendance * 0.3 + finalExam * 0.7;
                    courseTotal += totalScore;
                    courseCount++;
                } else {
                    double examScore = finalExam;
                    courseTotal += examScore;
                    courseCount++;
                }
            }

            double average = courseTotal / courseCount;
            totalAverage += average;
            studentCount++;
            System.out.println(student.getStudentId() + " " + student.getName() + " " + (int) average);
        }

        if (studentCount > 0) {
            double classAverage = totalAverage / studentCount;
            System.out.println(classAverage);
        } else {
            System.out.println("No students found");
        }
    }

    private void calculateCourseAverages() {
        List<String> courseNames = new ArrayList<>();
        Set<String> courseSet = new HashSet<>();

        for (Student student : students.values()) {
            for (String courseName : student.getGrades().keySet()) {
                if (courseSet.add(courseName)) {
                    courseNames.add(courseName);
                }
            }
        }

        Collections.sort(courseNames);

        for (String courseName : courseNames) {
            double attendanceTotal = 0.0, finalExamTotal = 0.0, totalScoreTotal = 0.0;
            int attendanceCount = 0, finalExamCount = 0, totalScoreCount = 0;

            for (Student student : students.values()) {
                Map<String, Integer[]> grades = student.getGrades();

                if (grades.containsKey(courseName)) {
                    Integer[] grade = grades.get(courseName);
                    Integer attendance = grade[0];
                    Integer finalExam = grade[1];

                    if (attendance != null) {
                        attendanceTotal += attendance;
                        attendanceCount++;
                    }

                    finalExamTotal += finalExam;
                    finalExamCount++;

                    if (attendance != null) {
                        double totalScore = attendance * 0.3 + finalExam * 0.7;
                        totalScoreTotal += totalScore;
                        totalScoreCount++;
                    }
                }
            }

            String attendanceAverage = attendanceCount > 0 ? String.format("%.0f", attendanceTotal / attendanceCount) : "-";
            String finalExamAverage = finalExamCount > 0 ? String.format("%.0f", finalExamTotal / finalExamCount) : "-";
            String totalScoreAverage = totalScoreCount > 0 ? String.format("%.0f", totalScoreTotal / totalScoreCount) : "-";
            System.out.println(courseName + " " + attendanceAverage + " " + finalExamAverage + " " + totalScoreAverage);
        }
    }

    private void calculateClassAverages() {
        Map<String, Double> classTotals = new HashMap<>();
        Map<String, Integer> classCounts = new HashMap<>();

        for (Student student : students.values()) {
            String classId = student.getStudentId().substring(0, 6);
            double classTotal = 0.0;
            int classCount = 0;

            Map<String, Integer[]> grades = student.getGrades();

            if (grades.isEmpty()) {
                continue;
            }

            for (Map.Entry<String, Integer[]> entry : grades.entrySet()) {
                Integer[] grade = entry.getValue();
                Integer attendance = grade[0];
                Integer finalExam = grade[1];

                if (attendance != null) {
                    double totalScore = attendance * 0.3 + finalExam * 0.7;
                    classTotal += totalScore;
                    classCount++;
                } else {
                    double examScore = finalExam;
                    classTotal += examScore;
                    classCount++;
                }
            }

            if (classCount > 0) {
                classTotals.put(classId, classTotals.getOrDefault(classId, 0.0) + classTotal);
                classCounts.put(classId, classCounts.getOrDefault(classId, 0) + classCount);
            }
        }

        List<Map.Entry<String, Double>> classAverages = new ArrayList<>(classTotals.entrySet());
        classAverages.sort(Comparator.comparing(Map.Entry::getKey));

        for (Map.Entry<String, Double> entry : classAverages) {
            String classId = entry.getKey();
            double classTotal = entry.getValue();
            int classCount = classCounts.get(classId);
            double classAverage = classTotal / classCount;

            System.out.println(classId + " " + (int) classAverage);
        }
    }
}

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

        while (scanner.hasNextLine()) {
            String input = scanner.nextLine();
            if (input.equals("end")) {
                break;
            }

            if (input.contains(" ")) {
                analyzer.addStudentGrade(input);
            } else {
                analyzer.addCourse(input);
            }
        }

        analyzer.calculateAverages();
    }
}

 

代码分析:

这是一个关于对学生课程成绩进行处理和计算的Java题目。下面是对该题目的分析和解答:
首先,我们需要定义一个表示课程的类和一个表示学生课程成绩的类。课程类(Course)应包含课程名称、课程性质和考核方式这三个属性。学生课程成绩类(StudentCourseGrade)应包含学号、姓名、课程名称、平时成绩和期末成绩这几个属性。

读取输入:按照指定的格式从标准输入读取课程信息和学生课程成绩信息,并将其存储在相应的数据结构中(课程列表、学生课程成绩列表)。
检查课程信息和学生课程成绩信息的正确性:对于每个学生课程成绩信息,检查课程名称是否在已输入的课程列表中存在,如果不存在,则输出错误信息。同时,检查学生课程成绩信息的数量是否与相应课程的考核方式匹配,如果不匹配,则输出错误信息。
计算学生课程总成绩平均分:按照学号由低到高排序,对于每个学生,根据其学号从学生课程成绩列表中获取对应的课程成绩信息,计算总成绩,并计算所有学生课程总成绩平均分。
计算单门课程成绩平均分:按照课程名称的字符顺序排序,对于每门课程,在学生课程成绩列表中找到对应的成绩信息,计算平时成绩平均分、期末考试平均分和总成绩平均分。
计算班级所有课程总成绩平均分:按照班级号由低到高排序,对于每个班级,根据学号的前6位获取对应的学生课程成绩信息,计算该班级的所有课程总成绩平均分。
输出结果:按照指定的格式输出学生课程总成绩平均分、单门课程成绩平均分和班级所有课程总成绩平均分。

在实现上述步骤时,需要使用合适的数据结构来存储课程列表、学生课程成绩列表以及其他辅助数据结构。为了简化问题的处理,可以使用Java中的集合类(例如List、Map)来存储这些数据。

 

类图及报表:

 

 

三. 采坑心得
在解决该题目时,需要注意以下几点:

需要进行输入数据的有效性检查,确保输入数据符合约束条件,如成绩范围、输入格式等。
需要正确处理异常情况,如课程名称不在已输入的课程列表中、考核方式和成绩数量不匹配等,确保程序的健壮性。
在计算平均分和排序时,需要注意处理没有成绩信息的学生和课程的情况,确保输出结果的完整性和正确性。
可以采用辅助方法来模块化代码,提高代码的可读性和可维护性。

四. 改进建议
针对该题目的编码改进,可以考虑以下方面:

引入异常处理机制,提高程序的健壮性和容错性,对输入数据进行更细致的检查和处理。
使用更合适的数据结构,如HashMap来存储课程和学生信息,提高数据的检索和操作效率。
考虑引入面向对象的设计思想,封装类的属性和方法,提高代码的可读性和可维护性。
增加日志记录和测试用例,方便调试和排查问题,确保程序的质量和稳定性。

五. 总结
通过解决这个题目,我对Java编程的相关知识点有了更深入的理解和应用。在编码过程中,我不仅学会了处理输入输出、字符串处理和数值计算等基本操作,还提高了编码的规范性和健壮性。在解决问题的过程中,我遇到了一些困难和挑战,但通过仔细分析和调试,最终得以解决。我还意识到自己在设计和优化代码方面还有一些进步的空间,需要进一步学习和研究。

posted on 2023-06-23 23:26  IDecideAll  阅读(58)  评论(0)    收藏  举报