答题判题程序(大作业1-3)
答题判题程序(大作业1-3)
一.前言
在过去的几周时间,设计并实现了三个版本的答题程序,模拟一个小型的测试系统。每个版本都在前一个版本的基础上进行了功能的扩展和改进。通过这些项目,不仅深化了对Java编程语言的理解,还掌握了如何设计复杂系统的能力。
PTA第一次作业
这是一个基础版本,主要涉及题目信息的输入和答案的判断。题量较小,难度较低,主要考察基本的字符串处理和逻辑判断能力。通过这个版本的实现,熟悉了基本的输入输出处理,并对题目和答案的基本匹配逻辑进行了梳理。
PTA第二次作业
在此版本中,引入了试卷信息和答卷信息的处理。题量增加,难度中等,要求设计更复杂的数据结构来管理题目与试卷的关系。通过这个版本的实现,学习了如何处理更复杂的数据结构和关系,并在程序中实现了基本的试卷和答卷匹配逻辑。
PTA第三次作业
这是最复杂的版本,增加了学生信息和删除题目信息的处理。题量大,难度高,需要处理更多的边界情况和异常输入。通过这个版本的实现,进一步增强了对复杂系统的理解和处理能力,特别是在处理异常和边界条件方面的能力。
二.设计于分析
PTA作业三次迭代后代码分析
SourceMontor报表
总行数: 143
语句数: 94
17.0% 的代码行包含分支语句,
0.7% 的代码行包含注释,
类和接口数量: 4
平均每个类有 2.5 个方法。
方法和复杂性
平均每个方法有 6.9 条语句。
最复杂的方法是 Main.process(),位于第 79 行。
复杂度为 10,
最大块深度为 6,
复杂性分析
最大复杂度: 10,
最深块所在行号: 107,最大块深度为 6,显示出代码某些部分可能过于复杂。
类图
Main 类
main(String[]): 主入口方法。
addTestPaper(String): 添加试卷的方法。
addAnswerSheet(String): 添加答题纸的方法。
process(): 处理流程的方法。
addQuestion(String): 添加问题的方法。
TestPaper 类
addQuestion(int, int): 添加问题的方法,接受两个整数参数。
getTotalScore(): 返回总分的方法。
Question类
属性:
id: 问题的唯一标识符。
content: 问题的实际内容。
answer: 问题的标准答案。
作用:
代表一个考试问题,包含问题的基本信息和正确答案
点击查看代码
class Question {
int id;
String content;
String answer;
public Question(int id, String content, String answer) {
this.id = id;
this.content = content;
this.answer = answer;
}
}
AnswerSheet类
属性:
testPaperId: 关联的试卷编号。
answers: 用户提交的答案列表。
作用:
代表一份答题纸,存储用户的答案并关联到特定的试卷。
点击查看代码
class AnswerSheet {
int testPaperId;
List<String> answers;
public AnswerSheet(int testPaperId, List<String> answers) {
this.testPaperId = testPaperId;
this.answers = answers;
}
}
TestPaper类
属性:
id: 试卷的唯一标识符。
questions: Map,将题目编号映射到该题目的分值。
方法:
addQuestion(int questionId, int score): 将题目及其分值添加到试卷中。
getTotalScore(): 计算试卷中所有题目的总分。
作用:
管理一个试卷的题目及其分值。
点击查看代码
class TestPaper {
int id;
Map<Integer, Integer> questions; // 题目编号到分值的映射
public TestPaper(int id) {
this.id = id;
this.questions = new LinkedHashMap<>();
}
public void addQuestion(int questionId, int score) {
questions.put(questionId, score);
}
public int getTotalScore() {
return questions.values().stream().mapToInt(Integer::intValue).sum();
}
}
Main类
属性:
questionBank: 存储所有问题的 Map。
testPapers: 存储所有试卷的 Map。
answerSheets: 存储所有答题纸的 List。
方法:
addQuestion(String input): 从输入字符串解析并添加问题。
addTestPaper(String input): 从输入字符串解析并添加试卷。
addAnswerSheet(String input): 从输入字符串解析并添加答题纸。
process(): 处理答题纸,验证答案并计算得分。
main(String[] args): 程序的入口,处理用户输入并调用其他方法。
作用:
管理整个考试系统的逻辑,包括问题、试卷和答题纸的添加和处理。
点击查看代码
public class Main {
Map<Integer, Question> questionBank = new HashMap<>();
Map<Integer, TestPaper> testPapers = new HashMap<>();
List<AnswerSheet> answerSheets = new ArrayList<>();
public void addQuestion(String input) {
String[] parts = input.split(" #");
int id = Integer.parseInt(parts[0].split(":")[1].trim());
String content = parts[1].split(":")[1].trim();
String answer = parts[2].split(":")[1].trim();
questionBank.put(id, new Question(id, content, answer));
}
public void addTestPaper(String input) {
String[] parts = input.split(" ");
int id = Integer.parseInt(parts[0].split(":")[1].trim());
TestPaper paper = new TestPaper(id);
for (int i = 1; i < parts.length; i++) {
String[] qAndScore = parts[i].split("-");
int questionId = Integer.parseInt(qAndScore[0]);
int score = Integer.parseInt(qAndScore[1]);
paper.addQuestion(questionId, score);
}
testPapers.put(id, paper);
}
三.踩坑心得
1. 输入格式解析
问题:正则表达式解析输入格式时可能会出现匹配错误,尤其是在处理复杂的输入格式时。
心得:确保正则表达式的准确性,并对每种可能的输入格式进行详尽的测试。可以通过添加日志或打印调试信息来检查每个步骤的解析结果。
2. 数据结构选择
问题:选择不当的数据结构可能导致效率低下。例如,使用List存储试卷的题目顺序和分值,可能会导致查找效率低。
心得:使用Map来存储题目和分值的对应关系,可以提高查找效率。在设计数据结构时,应根据使用场景选择合适的结构。
3. 重复数据处理
问题:在处理重复的题目编号、试卷编号或学生编号时,可能会导致数据覆盖或逻辑错误。
心得:在添加数据之前,先检查是否已经存在相同的编号,并在发现重复时输出相应的提示信息。
4. 异常处理
问题:处理输入时可能出现格式错误或数据不一致的问题。
心得:为每种可能的异常情况添加异常处理逻辑,并输出有意义的错误信息。这样可以帮助快速定位问题。
5. 删除题目逻辑
问题:在处理删除题目时,可能会忽略对试卷中引用该题目的处理,导致评分错误。
心得:在删除题目时,确保在评估答案时正确处理已删除的题目,并输出相应的提示信息。
6. 边界条件
问题:在处理答卷信息时,可能会出现缺失答案或多余答案的情况。
心得:在解析答案时,确保处理所有可能的边界情况,例如缺失答案时给出默认值,并在输出中标记答案缺失的情况。
7. 输出格式
问题:输出格式不符合要求,可能导致结果不正确或不易读。
心得:在输出结果时,严格按照要求的格式生成输出,并在开发过程中多次验证输出格式的正确性。改进建议
8.优化
针对目前的实现,可进行如下改进:
代码重构:通过重构复杂的函数,减少代码重复,提高可读性和可维护性。在重构过程中,我们可以使用设计模式来优化代码结构,提高代码的可读性和可维护性。
增强测试覆盖:增加更多的测试用例,特别是针对异常和边界情况的测试,以提高系统的鲁棒性。通过增加测试覆盖,我们可以更好地确保系统的正确性和稳定性。
优化数据结构:考虑使用更高效的数据结构,以提高系统的性能。在优化数据结构的过程中,我们可以使用更高效的算法和数据结构来提高系统的性能。
四.总结
通过这三个项目的开发,不仅提高了编程能力,还学会了如何设计和实现复杂的系统。以下是在这个过程中学到的关键知识:
面向对象设计原则:通过合理的类设计和职责分配,提高了系统的可扩展性和可维护性。学会了如何使用面向对象的原则来设计复杂的系统,并提高了对面向对象编程的理解。
异常处理:通过完善的异常处理机制,增强了系统的鲁棒性。学会了如何设计和实现健壮的异常处理机制,并提高了对异常处理的理解和应用能力。
测试驱动开发:通过编写全面的测试用例,确保了系统的正确性和稳定性。学会了如何使用测试驱动开发的方法来提高系统的质量,并提高了对测试驱动开发的理解和应用能力。
通过本次学习,我们对Java编程和软件设计有了更深入的理解,也期待在未来的学习中能够继续提高自己的技能。我们意识到,编写高质量的软件需要的不仅仅是编程技巧,还需要良好的设计和规划能力,以及对软件工程原则的深刻理解。在未来的学习和工作中,我们将继续探索和应用这些原则,以开发出更高效、更可靠的软件系统。
在这三个项目中,还学会了如何在团队中协作。通过与团队成员的沟通和合作,我们能够更好地理解和解决问题。这种协作能力不仅在项目开发中至关重要,也将在我们未来的职业生涯中发挥重要作用。
此外,还认识到持续学习和改进的重要性。在软件开发领域,技术和工具不断更新,我们需要不断学习和适应,以保持竞争力。在未来的学习中,将继续关注行业的发展趋势,学习新的技术和方法,以提高我们的专业水平。
总之,通过这三个项目的开发,不仅提高了技术能力,也增强了对软件开发过程的理解。这些经验和技能将为未来的学习和职业发展打下坚实的基础。期待在未来的学习和工作中,能够继续应用和发展这些技能,以实现职业目标。
五.附录源码
点击查看代码
import java.util.*;
class Question {
int id;
String content;
String answer;
public Question(int id, String content, String answer) {
this.id = id;
this.content = content;
this.answer = answer;
}
}
class TestPaper {
int id;
Map<Integer, Integer> questions; // 题目编号到分值的映射
public TestPaper(int id) {
this.id = id;
this.questions = new LinkedHashMap<>();
}
public void addQuestion(int questionId, int score) {
questions.put(questionId, score);
}
public int getTotalScore() {
return questions.values().stream().mapToInt(Integer::intValue).sum();
}
}
class AnswerSheet {
int testPaperId;
List<String> answers;
public AnswerSheet(int testPaperId, List<String> answers) {
this.testPaperId = testPaperId;
this.answers = answers;
}
}
public class Main {
Map<Integer, Question> questionBank = new HashMap<>();
Map<Integer, TestPaper> testPapers = new HashMap<>();
List<AnswerSheet> answerSheets = new ArrayList<>();
public void addQuestion(String input) {
String[] parts = input.split(" #");
int id = Integer.parseInt(parts[0].split(":")[1].trim());
String content = parts[1].split(":")[1].trim();
String answer = parts[2].split(":")[1].trim();
questionBank.put(id, new Question(id, content, answer));
}
public void addTestPaper(String input) {
String[] parts = input.split(" ");
int id = Integer.parseInt(parts[0].split(":")[1].trim());
TestPaper paper = new TestPaper(id);
for (int i = 1; i < parts.length; i++) {
String[] qAndScore = parts[i].split("-");
int questionId = Integer.parseInt(qAndScore[0]);
int score = Integer.parseInt(qAndScore[1]);
paper.addQuestion(questionId, score);
}
testPapers.put(id, paper);
}
public void addAnswerSheet(String input) {
String[] parts = input.split(" #");
int testPaperId = Integer.parseInt(parts[0].split(":")[1].trim());
List<String> answerList = new ArrayList<>();
for (int i = 1; i < parts.length; i++) {
answerList.add(parts[i].split(":")[1].trim());
}
answerSheets.add(new AnswerSheet(testPaperId, answerList));
}
public void process() {
for (TestPaper paper : testPapers.values()) {
if (paper.getTotalScore() != 100) {
System.out.println("alert: full score of test paper" + paper.id + " is not 100 points");
}
}
for (AnswerSheet sheet : answerSheets) {
TestPaper paper = testPapers.get(sheet.testPaperId);
if (paper == null) {
System.out.println("The test paper number does not exist");
continue;
}
int totalScore = 0;
int answerIndex = 0;
StringBuilder scoreOutput = new StringBuilder();
for (Map.Entry<Integer, Integer> entry : paper.questions.entrySet()) {
int questionId = entry.getKey();
int score = entry.getValue();
Question question = questionBank.get(questionId);
if (answerIndex < sheet.answers.size()) {
String givenAnswer = sheet.answers.get(answerIndex);
boolean isCorrect = givenAnswer.equals(question.answer);
System.out.println(question.content + "~" + givenAnswer + "~" + (isCorrect ? "true" : "false"));
if (isCorrect) {
totalScore += score;
scoreOutput.append(score).append(" ");
} else {
scoreOutput.append("0 ");
}
} else {
System.out.println("answer is null");
scoreOutput.append("0 ");
}
answerIndex++;
}
System.out.println(scoreOutput.toString().trim() + "~" + totalScore);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Main examSystem = new Main();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (line.equals("end")) {
break;
}
if (line.startsWith("#N:")) {
examSystem.addQuestion(line);
} else if (line.startsWith("#T:")) {
examSystem.addTestPaper(line);
} else if (line.startsWith("#S:")) {
examSystem.addAnswerSheet(line);
}
}
examSystem.process();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」