OOP 第4-6次题目总结
目录一,前言
答题判题系统-4
知识点总结:
1.在这次答题判题系统中对输入信息的数据处理更加严格,复杂,对输入不同类型数据的处理要能熟练使用Sring类进行符串的拼接、分割和修改。
2.使用Map(如HashMap或LinkedHashMap)来存储题目 试卷 标准答案 答卷 学生等信息,以便根据编号快速查找。
3.在部分地方,使用数组或者链表存储数据,如:答卷类里使用列表来存储答题信息等。
4.对逻辑的控制要清晰且合理,如首先判断输入的类型(题目信息、试卷信息、学生信息、答题信息、删除题目信息),当处理删除题目信息时,更新试卷信息和答题信息中对应题目的状态,还有答题评分逻辑,要根据标准答案判断学生答案是否正确,并计算得分。
题量分析
1.题目信息:根据输入格式,可能有多道题目(单选,多选,填空等类型)信息输入。
2.试卷信息:可能有多张试卷信息输入。
3.学生信息:只输入一次学生信息,但可能包含多个学生。
4.答题信息:可能有多张答题信息输入,每张答题信息对应一个学生的一张试卷。
5.删除题目信息:可能有多条删除信息输入。
难度分析
我认为这次题目在前三次题目的基础上难度增加了不少,比如需要处理更加多种的类型输入,并正确解析它们,将数据存储进相应的地方。需要处理删除题目信息后的逻辑,逻辑因为题目类型的多样化更加复杂,更新相关数据结构需要缜密的逻辑思考。同理答题评分部分逻辑的处理也是一样。
家居强电电路模拟程序-1
知识点总结:
1.由于智能家居系统需要定义多个类来表示不同的设备,所以典型运用到了面向对象编程。
2.使用Map或HashMap来存储设备信息,以便通过设备标识符和编号快速查找设备对象。
3.使用简单的算术计算来处理设备工作状态的关系(如灯亮度、风扇转速)。
4.对字符串的处理需要解析输入字符串来获取设备信息和连接信息。还需要使用字符串分割来提取设备标识符、编号和引脚编号等。
题量分析
本题要求设计一个智能家居强电电路模拟系统,涉及多个设备类型和复杂的连接关系。需要处理设备信息、连接信息、控制设备调节信息等多种输入数据。输出要求详细,需要按照特定格式输出所有设备的状态或参数。但这只是粗略的设计,并且只用考虑到串联一两个设备的情况,所以作为一道时间一周的大题题量适中偏简。
难度分析
需要深入理解面向对象编程的概念,并正确设计设备类及其方法。以及掌握数据结构和算法的基础知识,来处理设备信息和连接关系。还要具备一定的字符串处理能力,以解析输入数据。输出格式要求严格,需要仔细处理输出逻辑和格式,但大部分只是一个初步设计,故难度适中。
家居强电电路模拟程序-2
知识点总结:
1.在家居强电电路模拟程序-1的基础上,增添了并联串联的输入,对输入数据的处理更加严格.
2.考虑更多设备的状态处理情况,并且要用缜密的逻辑进行精确的分析。
3.运用comparable接口重写compareTo方法来使用Collections类中的sort排序处理输出设备信息的次序。
题量分析
本题量适中,在1的基础上增添了其他的信息,涵盖了从基本的数据结构到复杂的模拟电路行为的多个方面。需要定义多个类、实现多个方法,并编写相应的输入/输出处理代码。
难度分析
本题难度适中偏上。难度主要体现在以下几个方面:
复杂性:需要处理多种不同类型的设备和复杂的连接关系。
细节性:需要仔细阅读题目要求,理解各种设备的工作原理和连接规则,确保模拟结果的准确性。
编程能力:需要熟练掌握Java编程语言,熟悉面向对象编程和异常处理等技术。同时,还需要具备一定的算法和数据结构基础。
调试能力:由于模拟系统的复杂性,可能需要进行大量的调试工作来确保系统的正常运行。
二,设计与分析
答题判题系统-4
点击查看题目内容
设计实现答题程序,模拟一个小型的测试,要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果。本题在答题判题程序-3基础上新增的内容统一附加在输出格式说明之后,用粗体标明。
输入格式:
程序输入信息分五种,信息可能会打乱顺序混合输入。
1、题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:
1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。
样例:#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
2、试卷信息
试卷信息为独行输入,一行为一张试卷,多张卷可分多行输入数据。 \
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值+" "+题目编号+"-"+题目分值+...
格式约束:
题目编号应与题目信息中的编号对应。
一行信息中可有多项题目编号与分值。
样例:#T:1 3-5 4-8 5-2
3、学生信息
学生信息只输入一行,一行中包括所有学生的信息,每个学生的信息包括学号和姓名,格式如下。
格式:"#X:"+学号+" "+姓名+"-"+学号+" "+姓名....+"-"+学号+" "+姓名
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
样例:
#S:1 #A:5 #A:22
1是试卷号
5是1号试卷的顺序第1题的题目答案
4、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序号与试 卷信息中的题目顺序相对应。答卷中:
格式:"#S:"+试卷号+" "+学号+" "+"#A:"+试卷题目的顺序号+"-"+答案内容+...
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
答案内容可以为空,即””。
答案内容中如果首尾有多余的空格,应去除后再进行判断。
答卷信息中仅包含试卷号、学号,而没有后续内容的,视为一张空白卷,为有效信息,不做格式错误处理。
样例:
#T:1 1-5 3-2 2-5 6-9 4-10 7-3
#S:1 20201103 #A:2-5 #A:6-4
1是试卷号
20201103是学号
2-5中的2是试卷中顺序号,5是试卷第2题的答案,即T中3-2的答案
6-4中的6是试卷中顺序号,4是试卷第6题的答案,即T中7-3的答案
注意:不要混淆顺序号与题号
5、删除题目信息
删除题目信息为独行输入,每一行为一条删除信息,多条删除信息可分多行输入。该信息用于删除一道题目信息,题目被删除之后,引用该题目的试卷依然有效,但被删除的题目将以0分计,同时在输出答案时,题目内容与答案改为一条失效提示,例如:”the question 2 invalid~0”
格式:"#D:N-"+题目号
格式约束:
题目号与第一项”题目信息”中的题号相对应,不是试卷中的题目顺序号。
本题暂不考虑删除的题号不存在的情况。
样例:
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end
输出:
alert: full score of test paper1 is not 100 points
1+1=~5~false
the question 2 invalid~0
20201103 Tom: 0 0~0
答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、试卷总分警示
该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100 分,该部分忽略,不输出。
格式:"alert: full score of test paper"+试卷号+" is not 100 points"
约束:有多张试卷时,按输入信息的先后顺序输出警示。
样例:alert: full score of test paper2 is not 100 points
2、答卷信息
一行为一道题的答题信息,根据试卷的题目的数量输出多行数据。
格式:题目内容+"~"+答案++"~"+判题结果(true/false)
约束:如果输入的答案信息少于试卷的题目数量,每一个缺失答案的题目都要输出"answer is null" 。
样例:
answer is null
3+2=~5~true
4+6=~22~false.
answer is null
3、判分信息
判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。
格式:学号+" "+姓名+": "+题目得分+" "+....+题目得分+"~"+总分
格式约束:
1、没有输入答案的题目、被删除的题目、答案错误的题目计0分
2、判题信息的顺序与输入答题信息中的顺序相同
样例:20201103 Tom: 0 0~0
根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。
4、被删除的题目提示信息
当某题目被试卷引用,同时被删除时,答案中输出提示信息。样例见第5种输入信息“删除题目信息”。
5、题目引用错误提示信息
试卷错误地引用了一道不存在题号的试题,在输出学生答案时,提示”non-existent question~”加答案。例如:
输入:
#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-4
end
输出:
alert: full score of test paper1 is not 100 points
non-existent question~0
20201103 Tom: 0~0
如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高,例如:
输入:
#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103
end
输出:
alert: full score of test paper1 is not 100 points
answer is null
20201103 Tom: 0~0
6、格式错误提示信息
输入信息只要不符合格式要求,均输出”wrong format:”+信息内容。
例如:wrong format:2 #Q:2+2= #4
7、试卷号引用错误提示输出
如果答卷信息中试卷的编号找不到,则输出”the test paper number does not exist”,答卷中的答案不用输出,参见样例8。
8、学号引用错误提示信息
如果答卷中的学号信息不在学生列表中,答案照常输出,判分时提示错误。参见样例9。
本次作业新增内容:
1、输入选择题题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
格式:"#Z:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式基本的约束与一般的题目输入信息一致。
新增约束:标准答案中如果包含多个正确答案(多选题),正确答案之间用英文空格分隔。
例如:
#Z:2 #Q:宋代书法有苏黄米蔡四家,分别是: #A:苏轼 黄庭坚 米芾 蔡襄
多选题输出:
输出格式与一般答卷题目的输出一致,判断结果除了true、false,增加一项”partially correct”表示部分正确。
多选题给分方式:
答案包含所有正确答案且不含错误答案给满分;包含一个错误答案或完全没有答案给0分;包含部分正确答案且不含错误答案给一半分,如果一半分值为小数,按截尾规则只保留整数部分。
例如:
#N:1 #Q:1+1= #A:2
#Z:2 #Q:党十八大报告提出要加强()建设。A 政务诚信 B 商务诚信 C社会诚信 D司法公信 #A:A B C D
#T:1 1-5 2-9
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-A C
end
输出:
alert: full score of test paper1 is not 100 points
1+1=~5~false
党十八大报告提出要加强()建设。A 政务诚信 B 商务诚信 C社会诚信 D司法公信~A C~partially correct
20201103 Tom: 0 4~4
2、输入填空题题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
格式:"#K:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式基本的约束与一般的题目输入信息一致。
例如:#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
填空题输出:
输出格式与一般答卷题目的输出一致,判断结果除了true、false,增加一项”partially correct”表示部分正确。
填空题给分方式:
答案与标准答案内容完全匹配给满分,包含一个错误字符或完全没有答案给0分,包含部分正确答案且不含错误字符给一半分,如果一半分值为小数,按截尾规则只保留整数部分。
例如:
#N:1 #Q:1+1= #A:2
#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
#T:1 1-5 2-10
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-瑶琴
end
输出:
alert: full score of test paper1 is not 100 points
1+1=~5~false
古琴在古代被称为:~瑶琴~partially correct
20201103 Tom: 0 5~5
3、输出顺序变化
只要是正确格式的信息,可以以任意的先后顺序输入各类不同的信息。比如试卷可以出现在题目之前,删除题目的信息可以出现在题目之前等。
例如:
#T:1 1-5 2-10
#N:1 #Q:1+1= #A:2
#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-古筝
end
输出:
alert: full score of test paper1 is not 100 points
1+1=~5~false
古琴在古代被称为:~古筝~false
20201103 Tom: 0 0~0
4、多张试卷信息
本题考虑多个同学有多张不同试卷的答卷的情况。输出顺序优先级为学号、试卷号,按从小到大的顺序先按学号排序,再按试卷号。
例如:
#T:1 1-5 2-10
#T:2 1-8 2-21
#N:1 #Q:1+1= #A:2
#S:2 20201103 #A:1-2 #A:2-古筝
#S:1 20201103 #A:1-5 #A:2-瑶琴或七弦琴
#S:1 20201104 #A:1-2 #A:2-瑟
#S:2 20201104 #A:1-5 #A:2-七弦琴
#X:20201103 Tom-20201104 Jack
#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
end
输出:
alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
1+1=~5~false
古琴在古代被称为:~瑶琴或七弦琴~true
20201103 Tom: 0 10~10
1+1=~2~true
古琴在古代被称为:~古筝~false
20201103 Tom: 8 0~8
1+1=~2~true
古琴在古代被称为:~瑟~false
20201104 Jack: 5 0~5
1+1=~5~false
古琴在古代被称为:~七弦琴~partially correct
20201104 Jack: 0 10~10
新增的题目异常情况的处理与一般题目相同,具体样例参考上一次大作业的样例说明:
答题判题程序-3题面.pdf
输入样例1:
多选题测试,不含删除。例如:
#N:1 #Q:1+1= #A:2
#Z:2 #Q:党十八大报告提出要加强()建设。A 政务诚信 B 商务诚信 C社会诚信 D司法公信 #A:A B C D
#T:1 1-5 2-9
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-A C
end
输出样例1:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
1+1=~5~false
党十八大报告提出要加强()建设。A 政务诚信 B 商务诚信 C社会诚信 D司法公信~A C~partially correct
20201103 Tom: 0 4~4
输入样例2:
填空题测试,不含删除。例如:
#N:1 #Q:1+1= #A:2
#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
#T:1 1-5 2-10
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-瑶琴
end
输出样例2:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
1+1=~5~false
古琴在古代被称为:~瑶琴~partially correct
20201103 Tom: 0 5~5
输入样例3:
乱序测试,不含删除。例如:
#T:1 1-5 2-10
#N:1 #Q:1+1= #A:2
#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-古筝
end
输出样例3:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
1+1=~5~false
古琴在古代被称为:~古筝~false
20201103 Tom: 0 0~0
输入样例4:
两个同学多张不同试卷的答卷,不含删除。例如:
#T:1 1-5 2-10
#T:2 1-8 2-21
#N:1 #Q:1+1= #A:2
#S:2 20201103 #A:1-2 #A:2-古筝
#S:1 20201104 #A:1-2 #A:2-瑟
#S:1 20201103 #A:1-5 #A:2-瑶琴或七弦琴
#S:2 20201104 #A:1-5 #A:2-七弦琴
#X:20201103 Tom-20201104 Jack
#K:2 #Q:古琴在古代被称为: #A:瑶琴或七弦琴
end
输出样例4:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
1+1=~5~false
古琴在古代被称为:~瑶琴或七弦琴~true
20201103 Tom: 0 10~10
1+1=~2~true
古琴在古代被称为:~古筝~false
20201103 Tom: 8 0~8
1+1=~2~true
古琴在古代被称为:~瑟~false
20201104 Jack: 5 0~5
1+1=~5~false
古琴在古代被称为:~七弦琴~partially correct
20201104 Jack: 0 10~10
类图
表格
源码分析
1.问题类:用于储存每道题目基本的信息
点击查看代码
class Question {
private int id;
private String content;
private String answer;
//有参构造
public Question(int id, String content, String answer) {
this.id = id;
this.content = content;
this.answer = answer;
}
//get set
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
}
2.试卷类:用于把多道题目联系起来构成一张试卷
点击查看代码
class TestPaper {
private int id; //试卷序号 第一张
private LinkedHashMap<Integer, Integer> questionsAndScores;//第一张试卷的题目序号和得分
//有参构造
public TestPaper(int id) {
this.id = id;
this.questionsAndScores = new LinkedHashMap<>();
}
//get set
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void addQuestion(int questionId, int score) {
questionsAndScores.put(questionId, score);
}
public LinkedHashMap<Integer, Integer> getQuestionsAndScores() {
return questionsAndScores;
}
//获取这个试卷中第i题的得分
public int oneScore(int i) {
return questionsAndScores.getOrDefault(i, 0); // 如果题目不存在,返回0
}
//判断该试卷中总分是否为100
public void ifTotalScore() {
int total = 0;
for (int score : questionsAndScores.values()) {
total += score;
}
if(total!=100){
System.out.printf("alert: full score of test paper%d is not 100 points\n",getId());
}
}
//删题
public void deleteQuestion(int questionId) {
questionsAndScores.remove(questionId);
}
//试卷错误地引用了不存在题号的试题
public boolean ifExisQues(Map<Integer, Question> questionsById) {
for (int questionId : questionsAndScores.keySet()) {
if (!questionsById.containsKey(questionId)) {
return false;
}
}
return true;
}
}
3.答卷类:用于储存学生写一张试卷回答的答案信息
点击查看代码
class AnswerSheet {
private int testPaperId;
private String num;//学生学号
private List<String> answers;
//参数构造
public AnswerSheet(int testPaperId, String num, List<String> answers) {
this.testPaperId = testPaperId;
this.num = num;
this.answers = new ArrayList<>();
}
//get set
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
public void addAnswer(String answer) {
answers.add(answer);
}
public int getTestPaperId() {
return testPaperId;
}
public void setTestPaperId(int testPaperId) {
this.testPaperId = testPaperId;
}
public void setAnswers(List<String> answers) {
this.answers = answers;
}
//得到一个包含所有答案的字符串数组。
public String[] getAnswers() {
return answers.toArray(new String[0]);
}
public boolean[] checkAnswers(Map<Integer, Question> questionsById) {
boolean[] results = new boolean[answers.size()];
int index = 0;
for (int questionId : questionsById.keySet()) {
if (index < answers.size() && answers.get(index) != null) {
Question question = questionsById.get(questionId);
results[index] = question.getAnswer().equals(answers.get(index));
} else {
results[index] = false; //没有答案或者超出范围
}
index++;
}
return results;
}
//把学号与map学生中的姓名匹配上
public String isMapname(Map<Integer, Student> students, String num) {
int id = Integer.parseInt(num);
// 从Map中查找学生
Student student = students.get(id);
// 如果找到学生,返回其姓名;否则返回null
return student != null ? student.getName() : null;
}
}
4.学生类:用于储存输入学生的信息
点击查看代码
class Student{
private String studentId;
private String name;
public Student(String studentId, String name) {
this.studentId = studentId;
this.name = name;
}
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
5.Main类
点击查看处理输入信息的代码
while (!(line = scanner.nextLine()).equals("end")) {
//输入题目信息
if (line.startsWith("#N:")) {
if (testPapersById.isEmpty() && answerSheetsById.isEmpty()) {
String[] parts = line.split(" ");
int id = 0;
num++;
String content = null;
String answer = null;
for (String part : parts) {
if (part.startsWith("#N:")) {
String[] idParts = part.split(":");
id = Integer.parseInt(idParts[1].trim());
} else if (part.startsWith("#Q:")) {
content = part.substring("#Q:".length()).trim();
} else if (part.startsWith("#A:")) {
answer = part.substring("#A:".length()).trim();
}
}
questionsById.put(id, new Question(id, content, answer));
}
}
//输入试卷信息
else if (line.startsWith("#T:")) {
String[] parts = line.substring("#T:".length()).trim().split(" ");
int id = Integer.parseInt(parts[0]);//第几张试卷
TestPaper testPaper = new TestPaper(id);
for (int i = 1; i < parts.length; i++) {
String[] qScoreParts = parts[i].split("-");
int questionId = Integer.parseInt(qScoreParts[0]);
int score = Integer.parseInt(qScoreParts[1]);
testPaper.addQuestion(questionId, score);
testPapersById.put(id, testPaper);
}
}
//输入学生信息
else if (line.startsWith("#X:")) {
String[] parts = line.substring("#X:".length()).trim().split("-");
for (String part : parts) {
String[] studentInfo = part.trim().split("\\s+"); // 使用空白字符分割id和name
if (studentInfo.length == 2) { // 确保id和name都存在
int studentId = Integer.parseInt(studentInfo[0]); // 假设id是整数
String name = studentInfo[1];
Student student = new Student(String.valueOf(studentId), name); // 使用String.valueOf确保id是String类型
Students.put(studentId, student); // 将Student对象添加到Map中
}
}
}
//输入答卷信息
else if (line.startsWith("#S:")) {
String[] parts = line.substring("#S:".length()).trim().split(" ");
int id = Integer.parseInt(parts[0]);
String studentId = parts[1];
AnswerSheet answersheet = new AnswerSheet(id, studentId, null);//????
for (int i = 2; i < parts.length; i++) {
if (parts[i].startsWith("#A:")) {
String[] questIdScore = parts[i].substring("#A:".length()).trim().split("-");
String answer = questIdScore[1];
answersheet.addAnswer(answer);
}
}
answerSheetsById.put(id, answersheet);
}
//输入删除题目信息
else if (line.startsWith("#D:N-")) {
Pattern pattern = Pattern.compile("#D:N-(\\d+)");
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String numberStr = matcher.group(1);
int number = Integer.parseInt(numberStr);
invalid = number;
TestPaper test = testPapersById.get(1);//???
test.deleteQuestion(number);
}
}
}
点击查看存储输入信息和打印结果的代码
TestPaper test = testPapersById.get(1);//test 是第一张试卷
test.ifTotalScore();
AnswerSheet answersheet = answerSheetsById.get(1);
String[] answer = answersheet.getAnswers();
boolean[] results = answersheet.checkAnswers(questionsById);
int total = 0, i = 0;
LinkedHashMap<Integer, Integer> questionsAndScores = test.getQuestionsAndScores();
for (int questionId : questionsAndScores.keySet()) {
Question question = questionsById.get(questionId);
if (question != null) {
String content = question.getContent();
i++;
if (content != null) {
System.out.println(content + "~" + answer[i - 1] + "~" + results[i - 1]);
}
}
}
if (test.ifExisQues(questionsById) == false) {
System.out.println("non-existent question~0");
} else {
if (invalid != 0) {
System.out.println("the question " + invalid + " invalid~0");
}
}
System.out.printf("%s %s:", answersheet.getNum(), answersheet.isMapname(Students, answersheet.getNum()));
for (i = 1; i <= num; i++) {
if (results[i - 1]) {
total = total + test.oneScore(i);
System.out.printf(" %d", test.oneScore(i));
} else {
System.out.printf(" 0");
}
}
System.out.printf("~%d", total);
家居强电电路模拟程序-1
类图
表格
源码分析
1.设备类(抽象类)
考虑到该题是将许多种类的设备串联起来,所以可以设置一个父类 设备类,将其余的设备都继承这个类,使其具有可拓展性。此外需要在设计一个getStatus的抽象方法用于获取设备状态。
点击查看设备类的代码
abstract class Device {
protected String id;
protected double inputVoltage=220;//输入的电压
public Device() {
}
public Device(String id, double inputVoltage) {
this.id = id;
this.inputVoltage = inputVoltage;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getInputVoltage() {
return inputVoltage;
}
public void setInputVoltage(double inputVoltage) {
this.inputVoltage = inputVoltage;
}
public abstract String getStatus();
}
2.继承设备类的其他电器类
根据题目依次设计开关,分档调速器,连续调速器,灯类,吊扇类。具体如下:
开关类:设计一个属性表示开关闭合情况的状态,复写所继承的getStatus抽象方法,添加了一个切换状态的方法。
点击查看代码
//开关
class SwitchController extends Device {
private boolean isOn=true;
public SwitchController() {
}
public SwitchController(String id, double inputVoltage, boolean isOn) {
super(id, inputVoltage);
this.isOn = isOn;
}
public boolean isOn() {
return isOn;
}
public void setOn(boolean on) {
isOn = on;
}
// 添加切换状态的方法(开变关,关变开)
public void toggle() {
this.isOn = !this.isOn;
}
@Override
//获取当前开关状态 (turned on或者closed)
public String getStatus() {
return isOn ? "turned on" : "closed";
}
}
分档调速器和连续调速器类:都需要设计一个lever属性用于表示该调速器的档次,复写getStatus方法,根据两种调速器计算档次的算法分别设计一个方法来计算,以及实现加减档操作的方法(注意挡位的范围)。
点击查看代码
//分挡调速器
class StepController extends Device {
private int level=0;//挡位
public StepController() {
}
public StepController(String id, double inputVoltage, int level) {
super(id, inputVoltage);
this.level = level;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public void addLever(){
if(this.level>=0&&this.level<=2){
this.level++;
}
}
public void reduceLever(){
if(level>=1&&level<=3){
level--;
}
}
//计算输出电压
public double calculateOutput(){
double v=220;
switch (level){
case 0:
v= 0;
break;
case 1:
v= inputVoltage*0.3;
break;
case 2:
v= inputVoltage*0.6;
break;
case 3:
v=inputVoltage*0.9;
break;
}
return v;
}
@Override
public String getStatus() {
return String.valueOf(this.level);
}
}
//连续调速器
class ContinuousController extends Device {
private double level=0.0;
public ContinuousController() {
}
public ContinuousController(String id, double inputVoltage, double level) {
super(id, inputVoltage);
this.level = level;
}
public void setLevel(double level) {
if (level < 0.0 || level > 1.0) {
throw new IllegalArgumentException("Invalid level for continuous controller");
}
this.level = level;
}
//计算输出电压
public double calculateOutput(){
return inputVoltage*level;
}
@Override
public String getStatus() {
return String.format("%.2f",this.level);
}
}
灯类和扇类:这两类都有一个显著特征,他们是受控设备,需要接受控制设备的调节来改变自己的状态,因为在设计过程中每次迭代都有电器设备的增加,所以将各种各样的灯和扇都抽象出来。写代码的时候通过控制设备的调节计算受控设备的状态来重写getStatus方法。
点击查看代码
abstract class Light extends Device{
public Light() {
}
public Light(String id, double inputVoltage) {
super(id, inputVoltage);
}
}
abstract class Fan extends Device{
public Fan() {
}
public Fan(String id, double inputVoltage) {
super(id, inputVoltage);
}
}
具体的受控设备:其继承灯类或扇类,根据特征的不同设计其独特的方法并都复写getStatus来获取状态。
点击查看代码
//白炽灯
class Bulb extends Light {
public Bulb() {
}
public Bulb(String id, double inputVoltage) {
super(id, inputVoltage);
}
@Override
public String getStatus() {
if (inputVoltage <= 9) {
return String.valueOf(0);
}
double value = (5.0/7.0)*inputVoltage+(300.0/7.0);
return String.valueOf((int)value);
}
}
//日光灯
class Fluorescent extends Light{
public Fluorescent() {
}
public Fluorescent(String id, double inputVoltage) {
super(id, inputVoltage);
}
@Override
public String getStatus() {
if(inputVoltage==0){
return String.valueOf(0);
}
else
return String.valueOf(180);
}
}
//吊扇
class CeilingFan extends Fan {
@Override
public String getStatus() {
double voltageDifference = inputVoltage;
if (voltageDifference < 80) {
return String.valueOf(0);
} else if (voltageDifference > 150) {
return String.valueOf(360);
} else {
double value = (inputVoltage- 80) / 70 * 280 + 80;
return String.valueOf((int)value);
}
}
}
Main类:
main方法
点击查看代码
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextLine()) {
String input = sc.nextLine();
if ("end".equalsIgnoreCase(input)) {
break;
}
processInput(input);
}
printDeviceStatus();
}
除了main方法我还设计了几个方法,分别是:处理输入信息的方法(processInput),将设备连接起来的方法(connectDevices),用于调整设备也可以说更新设备状态的方法(adjustController),最后还有一个打印设备信息的方法(printDeviceStatus)。通过读取设备信息将设备连接起来后更新设备状态再将其状态打印出来这个逻辑来实现需求。
点击查看代码
private static void printDeviceStatus() {
for (Map.Entry<String, Device> entry : deviceMap.entrySet()) {
String key = entry.getKey();
Device device = entry.getValue();
if(device instanceof SwitchController){
SwitchController switchDevice = (SwitchController) device;
if(switchDevice.isOn()){
voltages = 0;}
else {
voltages = 220;
}
System.out.println("@"+key+":"+switchDevice.getStatus());
}
if(device instanceof StepController){
StepController stepController = (StepController) device;
voltages=stepController.calculateOutput();
System.out.println("@"+key+":"+stepController.getStatus());
}
if(device instanceof ContinuousController){
ContinuousController continuousController = (ContinuousController) device;
voltages = continuousController.calculateOutput();
System.out.println("@"+key+":"+continuousController.getStatus());
}
if(device instanceof Bulb){
Bulb bulb = (Bulb) device;
bulb.setInputVoltage(voltages);
System.out.println("@"+key+":"+bulb.getStatus());
}
if(device instanceof Fluorescent){
Fluorescent fluorescent = (Fluorescent) device;
fluorescent.setInputVoltage(voltages);
System.out.println("@"+key+":"+fluorescent.getStatus());
}
if(device instanceof CeilingFan){
CeilingFan ceilingFan = (CeilingFan) device;
ceilingFan.setInputVoltage(voltages);
System.out.println("@"+key+":"+ceilingFan.getStatus());
}
}
}
//对输入进行处理
private static void processInput(String input) {
String[] parts = input.split("\\s+");
String action = parts[0];
if (action.startsWith("[")) {
connectDevices(parts);
} else if (action.startsWith("#")) {
adjustController(parts[0]);//输入的时候就处理
}
}
private static void connectDevices(String[] parts) {
parts[0] = parts[0].substring(1);
parts[1] = parts[1].substring(0, parts[1].length() - 1);//除去[或者]
if (parts[0].contains("-") && parts[1].contains("-")) {
String device1 = parts[0].split("-")[0];
String device2 = parts[1].split("-")[0];//除去-引脚
Device deviceA = null;
Device deviceB = null;
switch (device1.charAt(0)) {
case 'K':
deviceA = new SwitchController();
break;
case 'F':
deviceA = new StepController();
break;
case 'L':
deviceA = new ContinuousController();
break;
case 'B':
deviceA = new Bulb();
break;
case 'R':
deviceA = new Fluorescent();
break;
case 'D':
deviceA = new CeilingFan();
break;
}
switch (device2.charAt(0)) {
case 'K':
deviceB = new SwitchController();
break;
case 'F':
deviceB = new StepController();
break;
case 'L':
deviceB = new ContinuousController();
break;
case 'B':
deviceB = new Bulb();
break;
case 'R':
deviceB = new Fluorescent();
break;
case 'D':
deviceB = new CeilingFan();
break;
}
deviceMap.put(device1, deviceA);
deviceMap.put(device2, deviceB);
}
}
//用于调整控制设备
private static void adjustController(String parts) {
//s为去除#的形式
String s = parts.substring(1);
String device = s.substring(0, 2);//设备名
if (s.startsWith("K")) {
Device k1 = deviceMap.get(device);
SwitchController k = (SwitchController) k1;
k.toggle();
} else if (s.startsWith("F")) {
String t = s.substring(2);//获取是+还是-
StepController f = (StepController) deviceMap.get(device);
if (t.equalsIgnoreCase("+"))
f.addLever();
else {
f.reduceLever();
}
} else if (s.startsWith("L")) {
String[] parts1 = s.split(":");
double level = Double.parseDouble(parts1[1]);
ContinuousController l = (ContinuousController) deviceMap.get(device);
l.setLevel(level);
}
}
家居强电电路模拟程序-2
类图
其实由类图就可以看出我这次设计的不合理,代码逻辑过于复杂,依赖和关联很严重,没有很好的遵循OOP的基本原则,这点我应该反思并重新设计。
表格
源码分析
这次题目是在1的基础上增添了几个新的受控设备和增加了并联电路的迭代。
此外我意识到随着受控设备的增加和并联电路的情况,我应该把控制设备和受控设备分开。如下:
点击查看代码
//控制设备
abstract class ControlDevice extends Device{
protected double OutVoltage=220;//输出电压
public ControlDevice() {
}
public ControlDevice(String id) {
super(id);
}
public double getOutVoltage() {
return OutVoltage;
}
public abstract void setOutVoltage();
}
//受控设备
abstract class beControlDevice extends Device{
protected int Resistance;
protected double VD;//电势差
public beControlDevice(int resistance, double VD) {
Resistance = resistance;
this.VD = VD;
}
public beControlDevice() {
}
public beControlDevice(String id) {
}
public double getVD() {
return VD;
}
public void setVD(double VD) {
this.VD = VD;
}
public int getResistance() {
return Resistance;
}
public void setResistance(int resistance) {
Resistance = resistance;
}
}
以及增加新的设备落地扇,由于在此次电路设计中要考虑电阻的情况,所以需要设计一个属性来反映电阻阻值( resistance)
点击查看代码
//落地扇
class AFloorFan extends beControlDevice{
public AFloorFan(int resistance, double VD) {
super(resistance, VD);
}
public AFloorFan(String id, int resistance) {
super(id);
resistance = 80;
}
public AFloorFan() {
}
@Override
public String getStatus() {
int speed = 0;
if(VD >= 140){
speed = 360;
}
else if(VD >=120){
speed = 260;
}
else if(VD>= 100){
speed = 160;
}
else{
speed = 80;
}
return String.valueOf(speed);
}
}
设计过程中,我设计了一个串联类(Series)和一个并联类(extends)继承设备类,我当时设计的时候是想把一个小的串联电路或者并联的电路当作一个整体的设备串联在电路中,但在连接设备的时候我不能处理好电压变化。
点击查看代码
//串联电路
class Series extends Device{
private LinkedHashMap<String,Device> deviceSeries = new LinkedHashMap<>();
private double Resistance = 0.0 ;
public Series(String id) {
super(id);
}
public Series() {
}
public Series(String id, LinkedHashMap<String, Device> deviceSeries) {
super(id);
this.deviceSeries = deviceSeries;
}
public LinkedHashMap<String, Device> getDeviceSeries() {
return deviceSeries;
}
public void setDeviceSeries(LinkedHashMap<String, Device> deviceSeries) {
this.deviceSeries = deviceSeries;
}
public double getResistance() {
return Resistance;
}
public void setResistance() {
for(Device device : deviceSeries.values()){
if(device instanceof beControlDevice){
Resistance = ((beControlDevice) device).Resistance;
}
}
}
@Override
public String getStatus() {
return null;
}
}
//并联电路
class Parallel extends Device{
private LinkedHashMap<String,Series> deviceParallel = new LinkedHashMap<>();
private double Resistance = 0.0;
public Parallel() {
}
public Parallel(String id, LinkedHashMap<String, Series> deviceParallel) {
super(id);
this.deviceParallel = deviceParallel;
}
public LinkedHashMap<String, Series> getDeviceParallel() {
return deviceParallel;
}
//计算并联总电阻
public void setDeviceParallel() {
double r1 = 0.0;//电阻之和
double r2 = 1.0;//电阻之积
for(Series series : deviceParallel.values()){
r1 = r1+series.getResistance();
r2 = r2*series.getResistance();
}
this.Resistance = r2/r1;
}
public double getResistance() {
return Resistance;
}
public void setResistance(double resistance) {
Resistance = resistance;
}
@Override
public String getStatus() {
return null;
}
}
Main类:main大体上是与题目1一样的设计思路,但是这次由于设备的增多,要考虑他们的分压情况,如将小部分的串联情况和并联电路的情况传进主线路中。
点击查看代码
//连接小串联设备 返回这个线路的map
private static LinkedHashMap connectSeriesDevices(String[] parts){// [ ] 的字符串
LinkedHashMap<String, Device> deviceSeriesMap = new LinkedHashMap<>();
for(int i = 1;i<parts.length;i=i+2){
if(parts[i].equalsIgnoreCase("OUT]")){
break;
}
String device = parts[i].split("-")[0];//得到设备名字
Device deviceA = null;
switch (device.charAt(0)) {//没有把具体的设备名字传进设备中 只在map中
case 'K':
deviceA = new SwitchController();
break;
case 'F':
deviceA = new StepController();
break;
case 'L':
deviceA = new ContinuousController();
break;
case 'B':
deviceA = new Bulb();
break;
case 'R':
deviceA = new Fluorescent();
break;
case 'D':
deviceA = new CeilingFan();
break;
case'A':
deviceA = new AFloorFan();
}
deviceSeriesMap.put(device,deviceA);
}
return deviceSeriesMap;
}
//处理并联电路
private static LinkedHashMap connectParallelDevices(String input){
// 首先找到 '[' 的位置
int startIndex = input.indexOf('[') + 1; // +1 是为了跳过 '[' 字符本身
// 然后找到 ']' 的位置
int endIndex = input.indexOf(']', startIndex);
// 使用 substring 方法提取 [ 和 ] 之间的子串
String result = input.substring(startIndex, endIndex);
String[] parts = result.split("\\s+");
LinkedHashMap<String,Series> deviceParallelMap = new LinkedHashMap<>();
for(int i=0;i<parts.length;i++){
for(String id :deviceSeriesMap.keySet())
if(id.equalsIgnoreCase(parts[i])){
Series series = deviceSeriesMap.get(id);
deviceParallelMap.put(parts[i],series);
}
}
return deviceParallelMap;
}
//连接设备(大串联)
private static void connectDevices(String[] parts) {
for(int i = 1;i<parts.length;i=i+2){
if(parts[i].equalsIgnoreCase("GND]")){
break;
}
String device = parts[i].split("-")[0];//得到设备名字
Device deviceA = null;
switch (device.charAt(0)) {//没有把具体的设备名字传进设备中 只在map中
case 'K':
deviceA = new SwitchController();
break;
case 'F':
deviceA = new StepController(device);
break;
case 'L':
deviceA = new ContinuousController();
break;
case 'B':
deviceA = new Bulb();
break;
case 'R':
deviceA = new Fluorescent();
break;
case 'D':
deviceA = new CeilingFan();
break;
case'A':
deviceA = new AFloorFan();
case'M':
for(String id:deviceParallelMap.keySet()){
if(id.equalsIgnoreCase(device)){
deviceA = deviceParallelMap.get(id);
}
}
}
deviceMap.put(device,deviceA);
}
}
在更新设备状态的时候需要做出计算并且调整
点击查看代码
//用于调整控制设备
private static void adjustController(String parts) {
//s为去除#的形式
String s = parts.substring(1);
if (s.startsWith("K")) {
for(String id:deviceMap.keySet()){
if(s.equalsIgnoreCase(id)){
Device k1 = deviceMap.get(s);
SwitchController k = (SwitchController) k1;
k.toggle();
break;
}
}
for(Series series: deviceSeriesMap.values()){
for(String id:series.getDeviceSeries().keySet()){
Device k1 = deviceMap.get(s);
SwitchController k = (SwitchController) k1;
k.toggle();
break;
}
}
}
else if (s.startsWith("F")) {
String device = s.substring(0, 2);//设备名
String t = s.substring(2);//获取是+还是-
StepController f = (StepController) deviceMap.get(device);
if (t.equalsIgnoreCase("+")){
f.addLever();
f.setOutVoltage();}
else {
f.reduceLever();
f.setOutVoltage();
}
}
else if (s.startsWith("L")) {
String device = s.substring(0, 2);//设备名
String[] parts1 = s.split(":");
double level = Double.parseDouble(parts1[1]);
ContinuousController l = (ContinuousController) deviceMap.get(device);
l.setLevel(level);
l.setOutVoltage();
}
}
private static void calculate(){
double R =0;
for(Device device:deviceMap.values()){
if(device instanceof beControlDevice){
R=R+((beControlDevice) device).getResistance();
}
if (device instanceof Series){
R=R+((Series) device).getResistance();
}
if(device instanceof Parallel){
((Parallel) device).setDeviceParallel();
R=R+((Parallel) device).getResistance();
}
}
double I = 0.0;
if(voltages!=0){
I = voltages/R;
for(Device device :deviceMap.values()){
if(device instanceof beControlDevice){
((beControlDevice) device).setVD(I*((beControlDevice) device).getResistance());
}
if(device instanceof Parallel){
for(Series series:((Parallel) device).getDeviceParallel().values()){
for(Device device1:series.getDeviceSeries().values()){
if(device1 instanceof beControlDevice){
((beControlDevice) device1).setVD(I*((beControlDevice) device1).getResistance());
}
}
}
}
}
}
}
三,踩坑心得
1.在电路系统-1中,由于受控设备数量多,对具体设备的状态处理不对,导致测试点一直过不去,比如
观察到错误的测试点都与白炽灯的输出错误有关,重新检查代码发现了获取白炽灯状态的处理有误。
修改后解决该问题。
2.初步写完代码后,运行结果总为空,对main方法进行单步调试
后发现对于设备的连接信息不能正确储存,从中体会到在设计的时候逻辑清晰能很好的规避这种逻辑问题。
3.在题目2输出设备信息的时候,我没有想到好方法能够将设备状态按照顺序输入,因此走了很多弯路,写了很多复杂麻烦且不能正确满足需求的方法,我应该直接运用comparable接口重写compareTo方法来使用Collections类中的sort排序处理输出设备信息的次序。这样才能正确输出。
四,改进建议
对于我设计的类,他们之间的关系没有设计清楚,我应该根据给出迭代的最终电路重新设计,考虑好电路之间的连接关系,以及更新设备的状态,运用OOP的设计模式来实现我的代码。对于电路系统-2要改进Main类中几个方法处理数据的情况以及正确打印设备状态信息的代码。
五,总结
对于这三次pta题目的设计,我深刻体会到了设计的重要性,一个系统设计好了可以说是成功了一大半,代码并不是最重要的。此外我对于HashMap的理解更加深刻,对于比较器和sort方法我应该进一步学习和研究。基本的设计模式我也应该在线下借助网络或者老师发的ppt进行复习加深印象。
改进建议:我认为题目语言的组织可能有些许不足,导致题目有些地方可能在理解上有些问题,我感觉有点吃力,希望老师编写题目的语言能够更加简明扼要。一点点小建议望老师能采纳,谢谢老师。