一、前言:
关于这三次的PTA大作业,我认为题目难度是超出了我的现象的,特别是每次的压轴迭代题,这压轴三道题全是迭代而来,息息相关,这也就意味着你如果第一次的设计没有做好,框架出现问题,后续改进的时候就只会越来越吃力甚至是需要把整个架构都推倒重来。最后一道题目的知识点包含也非常广泛,例如正则表达式的运用,接口的创建,集合的用法等等。这些在当时刚接触java的我来说确实有点力不从心了。但是对于这三次大作业的题目量来看的话其实并不算多,第一次作业只有五道题,第二次作业只有四道题,而第三次只有三道题,所以重心还是在最后一题上。但是由于i我的固化思维,我认为面向对象这门课与c语言的差别并不显著,导致了我并没有能够全部完成最后一题的实现。
二、设计与分析:
PTA第一次作业:
关于第一次的PTA作业,能看出老师是让我们初步认识Java这一门计算机语言,所以前四道题都是基础类型的了解和运用,类似于设计一个类,类与对象的使用等基础知识。而最后一道题目则完全不是和它们一个量级,尽管老师已经提醒,但是对于我来说仍然是一个难以逾越的山峰。因为前几道题目除了语法与c语言不同之外其他没有太大区别,所以我都拿到了分数,而最后一题却是使我失去了信心。这里我们列举一道前面的题目。
题目描述
创建学生类,包含
属性:学号(String)、姓名(String)、语文成绩(int)、数学成绩(int)、物理成绩(int)
方法:计算总分、计算平均分
输入5个学生的信息,将每个学生的信息封装在一个学生对象中。
按输入顺序依次输出5个学生的总分、平均分(精确到小数点后两位,舍去部分按四舍五入规则计入最后一位)。
浮点数保留小数的相关知识可参考:
https://blog.csdn.net/huaishuming/article/details/17752365
注意:未用学生类对象封装数据的,本题计0分
输入格式:
5个学生信息,每个学生信息格式:
学号+英文空格+姓名+英文空格+语文成绩+英文空格+数学成绩+英文空格+物理成绩
例如:
22201311 张琳 80 80 80
22201312 黄昊 66 82 81
22201313 李少辰 77 76 80
22201314 袁婷 62 79 90
22201315 朱哲一 74 98 94
输出格式:
5个学生信息,每个学生信息格式:
学号+英文空格+姓名+英文空格+总成绩+英文空格+平均分
例如:
22201311 张琳 240 80.00
22201312 黄昊 229 76.33
22201313 李少辰 233 77.67
22201314 袁婷 231 77.00
22201315 朱哲一 266 88.67
输入样例:
在这里给出一组输入。例如:
22201311 张琳 80 80 80
22201312 黄昊 66 82 81
22201313 李少辰 77 76 80
22201314 袁婷 62 79 90
22201315 朱哲一 74 98 94
输出样例:
在这里给出相应的输出。例如:
22201311 张琳 240 80.00
22201312 黄昊 229 76.33
22201313 李少辰 233 77.67
22201314 袁婷 231 77.00
22201315 朱哲一 266 88.67
点击查看代码
import java.util.*;
import java.text.*;
import java.math.*;
class Student{
private String studentID;
private String name;
private int chineseScore;
private int mathScore;
private int physicsScore;
Student() {
}
public String getStudentID(){
return studentID;
}
public String getName(){
return name;
}
public Student(String studentID,String name, int chineseScore, int mathScore, int physicsScore)
{
this.studentID = studentID;
this.name = name;
this.chineseScore = chineseScore;
this.mathScore = mathScore;
this.physicsScore = physicsScore;
}
public int calculateTotalScore() {
return chineseScore + mathScore + physicsScore;
}
public double calculateAverageScore(){
return ((chineseScore + mathScore + physicsScore) / 3.00);
}
public String formatAverage(){
DecimalFormat df = new DecimalFormat("0.00");
return df.format(calculateAverageScore());
}
}
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
Student [] students = new Student[5];
for(int i=0;i<5;i++){
String studentID = scanner.next();
String name = scanner.next();
int chineseScore = scanner.nextInt();
int mathScore = scanner.nextInt();
int physicsScore = scanner.nextInt();
students[i] = new Student(studentID,name,chineseScore,mathScore,physicsScore);
}
for(Student student : students){
int sum = student.calculateTotalScore();
String averages = student.formatAverage();
System.out.println(student.getStudentID() + " " + student.getName() + " " + sum + " " + averages);
}
}
}
这道题目是一个简单的类与数组的使用,我在这里就不具体分析了。
下面是第一次作业的最后一题
题目描述
设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分三部分:
1、题目数量
格式:整数数值,若超过1位最高位不能为0,
样例:34
2、题目内容
一行为一道题,可以输入多行数据。
格式:"#N:"+题号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
样例:#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
3、答题信息
答题信息按行输入,每一行为一组答案,每组答案包含第2部分所有题目的解题答案,答案的顺序号与题目题号相对应。
格式:"#A:"+答案内容
格式约束:答案数量与第2部分题目的数量相同,答案之间以英文空格分隔。
样例:#A:2 #A:78
2是题号为1的题目的答案
78是题号为2的题目的答案
答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、题目数量
格式:整数数值,若超过1位最高位不能为0,
样例:34
2、答题信息
一行为一道题的答题信息,根据题目的数量输出多行数据。
格式:题目内容+" ~"+答案
样例:1+1=~2
2+2= ~4
3、判题信息
判题信息为一行数据,一条答题记录每个答案的判断结果,答案的先后顺序与题目题号相对应。
格式:判题结果+" "+判题结果
格式约束:
1、判题结果输出只能是true或者false,
2、判题信息的顺序与输入答题信息中的顺序相同
样例:true false true
输入样例1:
单个题目。例如:
1
N:1 #Q:1+1= #A:2
A:2
end
输出样例1:
在这里给出相应的输出。例如:
1+1=~2
true
输入样例2:
单个题目。例如:
1
N:1 #Q:1+1= #A:2
A:4
end
输出样例2:
在这里给出相应的输出。例如:
1+1=~4
false
输入样例3:
多个题目。例如:
2
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
A:2 #A:4
end
输出样例3:
在这里给出相应的输出。例如:
1+1=~2
2+2=~4
true true
输入样例4:
多个题目。例如:
2
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
A:2 #A:2
end
输出样例4:
在这里给出相应的输出。例如:
1+1=~2
2+2=~2
true false
输入样例5:
多个题目,题号顺序与输入顺序不同。例如:
2
N:2 #Q:1+1= #A:2
N:1 #Q:5+5= #A:10
A:10 #A:2
end
输出样例5:
在这里给出相应的输出。例如:
5+5=~10
1+1=~2
true true
输入样例6:
含多余的空格符。例如:
1
N:1 #Q: The starting point of the Long March is #A:ruijin
A:ruijin
end
输出样例6:
在这里给出相应的输出。例如:
The starting point of the Long March is~ruijin
true
输入样例7:
含多余的空格符。例如:
1
N: 1 #Q: 5 +5= #A:10
A:10
end
输出样例7:
在这里给出相应的输出。例如:
5 +5=~10
true
设计建议:
以下是针对以上题目要求的设计建议,其中的属性、方法为最小集,实现代码中可根据情况添加所需的内容:
题目类(用于封装单个题目的信息):
属性:题目编号、题目内容、标准答案-standardAnswer
方法:数据读写set\get方法、
判题方法(答案-answer):判断答案-answer是否符合标准答案-standardAnswer
试卷类(用于封装整套题目的信息)
属性:题目列表(题目类的对象集合)、题目数量
方法:判题方法(题号-num、答案-answer):判断答案-answer是否符合对应题号的题目标准答案-standardAnswer
保存题目(题号-num、题目-question):将题目保存到题目列表中,保存位置与num要能对应
答卷类(用于封装答题信息)
属性:试卷(试卷类的对象)、答案列表(保存每一题的答案)、判题列表(保存每一题的判题结果true/false)
方法:判题方法(题号-num):判断答案列表中第num题的结果是否符合试卷中对应题号的题目标准答案
输出方法(题号-num):按照题目的格式要求,输出题号为num的题目的内容和答题结果。
保存一个答案(题号-num,答案-answer):保存题号为num的题目的答题结果answer。
点击查看代码
import java.util.*;
class Question {
private int number;
private String content;
private String standardAnswer;
public Question(int number, String content, String standardAnswer) {
this.number = number;
this.content = content;
this.standardAnswer = standardAnswer;
}
public boolean judgeAnswer(String answer) {
return answer.equals(standardAnswer);
}
public String toString() {
return content + "~" + standardAnswer;
}
public int getnumber(){
return this.number;
}
}
class ExamPaper {
private List<Question> questions;
private Question question;
private int a;
public ExamPaper(int a) {
this.questions = new ArrayList<>();
this.a = a;
}
public void addQuestion(Question question) {
questions.add(question);
}
public boolean judgeAnswer(int number, String answer) {
return questions.get(number - 1).judgeAnswer(answer);
}
public String getQuestionInfo(int number) {
return questions.get(number - 1).toString();
}
public void sort(){
for(int x=0;x<a-1;x++){
for(int y = 0;y<a-1;y++){
if(questions.get(y).getnumber()>questions.get(y+1).getnumber()){
question = questions.get(y);questions.set(y,questions.get(y+1));questions.set(y+1,question);
}
}
}
}
}
class AnswerSheet {
private ExamPaper examPaper;
private List<String> answers;
private List<Boolean> judgeResults;
public AnswerSheet(ExamPaper examPaper) {
this.examPaper = examPaper;
this.answers = new ArrayList<>();
this.judgeResults = new ArrayList<>();
}
public void saveAnswer(String answer) {
answers.add(answer);
}
public void judgeAnswers() {
for (int i = 0; i < answers.size(); i++) {
String answer = answers.get(i);
boolean result = examPaper.judgeAnswer(i + 1, answer);
judgeResults.add(result);
}
}
public void printResults() {
for (int i = 0; i < answers.size(); i++) {
System.out.println(examPaper.getQuestionInfo(i + 1));
}
for (int i = 0; i < answers.size(); i++) {
System.out.printf("%s",judgeResults.get(i));
if(i==answers.size()-1){
System.out.println();
}else{
System.out.printf(" ");
}
}
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int questionCount = scanner.nextInt();
scanner.nextLine();
ExamPaper examPaper = new ExamPaper(questionCount);
for (int i = 0; i < questionCount; i++) {
String line = scanner.nextLine();
String[] parts = line.split(" #");
int number = Integer.parseInt(parts[0].split(":")[1].trim());
String content = parts[1].split(":")[1].trim();
String standardAnswer =parts[2].split(":")[1].trim();;
examPaper.addQuestion(new Question(number, content, standardAnswer));
}
examPaper.sort();
AnswerSheet answerSheet = new AnswerSheet(examPaper);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.equals("end")) {
break;
}
String[] answers = line.split(" ");
for (String answer : answers) {
if (answer.startsWith("#")) {
String ans = answer.substring(3);
answerSheet.saveAnswer(ans);
}
}
}
answerSheet.judgeAnswers();
answerSheet.printResults();
}
}
由于第一次接触到类的设计以及代码的完成,导致我一开始虽然可以通过测试点但是却没用合理地使用类,而是一股脑地把他放到Main中,这虽然可以通过测试点,但是却是在自欺欺人,因为这完全脱离了我们这门课程的初衷,一开始我还沾沾自喜地认为只花了一点时间就拿到了足够及格的分数,认为这道题目也不是那么可怕,但是当我意识到这样行不通的时候时间已经所剩无几,这也导致我整个三次作业的设计都将成为一团乱麻。好在我通过蔡老师在题目下方的设计建议临时补救,设计了三个类,但也仅仅是三个类。所以我有很多测试点无法通过,我也就抱着侥幸的心理完成了这一次的作业。
下面是第二次作业
首先是第二次作业的第一题,这道题目引入了接口的使用,导致我一开始并不能够将这道题目完成,后面通过线上课程以及查询资料理解了接口。
题目描述
编写手机类(MobilePhone),含有type(型号,String类型)、price(价格,int类型)属性,要求该类实现Comparable接口,重写compareTo方法,实现按照price的大小来确定两个手机对象的大小关系。
在链表中添加三个手机对象(从键盘输入),通过Collections类的sort方法对链表中的对象按照price升序排序。输入第四个手机对象的信息,并查找它的price是否与链表中某个对象的price相同。
输入格式:
先输入三部手机的型号、价格信息
再输入要查找的第四部手机的型号、价格信息
每部手机信息的格式如:Redmi9A 599
输出格式:
先输出三部手机排序前的信息
再输出三部手机排序后的信息
最后输出第四部手机是否与前面某部手机价格相同
具体格式参考输出样例
输入样例1:
在这里给出一组输入,第四部手机与前三部中某一部价格相同。例如:
HONOR70 2699
MI12 3499
VIVOS15 3299
RedmiK50 2699
输出样例1:
在这里给出相应的输出,第四部手机与前三部中某一部价格相同。例如:
排序前,链表中的数据:
型号:HONOR70,价格:2699
型号:MI12,价格:3499
型号:VIVOS15,价格:3299
排序后,链表中的数据:
型号:HONOR70,价格:2699
型号:VIVOS15,价格:3299
型号:MI12,价格:3499
RedmiK50与链表中的HONOR70价格相同
输入样例2:
在这里给出一组输入,第四部手机与前面三部的价格都不同。例如:
RedmiNote9 1349
HonorX30 1699
VIVOT2X 1599
OPPOk10 2199
输出样例2:
在这里给出相应的输出,第四部手机与前面三部的价格都不同。例如:
排序前,链表中的数据:
型号:RedmiNote9,价格:1349
型号:HonorX30,价格:1699
型号:VIVOT2X,价格:1599
排序后,链表中的数据:
型号:RedmiNote9,价格:1349
型号:VIVOT2X,价格:1599
型号:HonorX30,价格:1699
链表中的对象,没有一个与OPPOk10价格相同的
点击查看代码
import java.util.*;
import java.util.Scanner;
class MobilePhone implements Comparable<MobilePhone> {
private String type;
private int price;
public MobilePhone(String type, int price) {
this.type = type;
this.price = price;
}
public String getType() {
return type;
}
public int getPrice() {
return price;
}
public int compareTo(MobilePhone other) {
return Integer.compare(this.price, other.price);
}
public String toString() {
return "型号:" + type + ",价格:" + price;
}
}
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<MobilePhone> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
String type = sc.next();
int price = sc.nextInt();
MobilePhone mobilePhone = new MobilePhone(type, price);
list.add(mobilePhone);
}
System.out.println("排序前,链表中的数据:");
for (MobilePhone m : list) {
System.out.println(m);
}
Collections.sort(list);
System.out.println("排序后,链表中的数据:");
for (MobilePhone m : list) {
System.out.println(m);
}
String typeToFind = sc.next();
int priceToFind = sc.nextInt();
MobilePhone mobilePhoneToFind = new MobilePhone(typeToFind, priceToFind);
boolean found = false;
for (MobilePhone m : list) {
if (m.getPrice() == mobilePhoneToFind.getPrice()) {
found = true;
System.out.println(typeToFind + "与链表中的" + m.getType() + "价格相同");
break;
}
}
if (!found) {
System.out.println("链表中的对象,没有一个与" + typeToFind + "价格相同的");
}
sc.close();
}
}
这段代码的精髓我认为是通过 Comparable 接口的实现,使得手机对象可以根据价格进行比较和排序。因此我也不过多的进行赘述了。
下面是最后一题
题目描述
设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-1基础上增补或者修改的内容。
要求输入题目信息、试卷信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分三种,三种信息可能会打乱顺序混合输入:
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、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序与试卷信息中的题目顺序相对应。
格式:"#S:"+试卷号+" "+"#A:"+答案内容
格式约束:答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
样例:#S:1 #A:5 #A:22
1是试卷号
5是1号试卷的顺序第1题的题目答案
22是1号试卷的顺序第2题的题目答案
答题信息以一行"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"
样例:3+2=5true
4+6=~22~false.
answer is null
3、判分信息
判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。
格式:题目得分+" "+....+题目得分+"~"+总分
格式约束:
1、没有输入答案的题目计0分
2、判题信息的顺序与输入答题信息中的顺序相同
样例:5 8 0~13
根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。
4、提示错误的试卷号
如果答案信息中试卷的编号找不到,则输出”the test paper number does not exist”,参见样例9。
设计建议:
参考答题判题程序-1,建议增加答题类,类的内容以及类之间的关联自行设计。
输入样例1:
一张试卷一张答卷。试卷满分不等于100。例如:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
S:1 #A:5 #A:22
end
输出样例1:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
2+2=22false
0 0~0
输入样例2:
一张试卷一张答卷。试卷满分不等于100。例如:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-70 2-30
S:1 #A:5 #A:22
end
输出样例2:
在这里给出相应的输出。例如:
1+1=5false
2+2=22false
0 0~0
输入样例3:
一张试卷、一张答卷。各类信息混合输入。例如:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-70 2-30
N:3 #Q:3+2= #A:5
S:1 #A:5 #A:4
end
输出样例:
在这里给出相应的输出。例如:
1+1=5false
2+2=4true
0 30~30
输入样例4:
试卷题目的顺序与题号不一致。例如:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 2-70 1-30
N:3 #Q:3+2= #A:5
S:1 #A:5 #A:22
end
输出样例:
在这里给出相应的输出。例如:
2+2=5false
1+1=22false
0 0~0
输入样例5:
乱序输入。例如:
N:3 #Q:3+2= #A:5
N:2 #Q:2+2= #A:4
T:1 3-70 2-30
S:1 #A:5 #A:22
N:1 #Q:1+1= #A:2
end
输出样例:
在这里给出相应的输出。例如:
3+2=5true
2+2=22false
70 0~70
输入样例6:
乱序输入+两份答卷。例如:
N:3 #Q:3+2= #A:5
N:2 #Q:2+2= #A:4
T:1 3-70 2-30
S:1 #A:5 #A:22
N:1 #Q:1+1= #A:2
S:1 #A:5 #A:4
end
输出样例:
在这里给出相应的输出。例如:
3+2=5true
2+2=22false
70 0~70
3+2=5true
2+2=4true
70 30~100
输入样例7:
乱序输入+分值不足100+两份答卷。例如:
N:3 #Q:3+2= #A:5
N:2 #Q:2+2= #A:4
T:1 3-7 2-6
S:1 #A:5 #A:22
N:1 #Q:1+1= #A:2
S:1 #A:5 #A:4
end
输出样例:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
3+2=5true
2+2=22false
7 0~7
3+2=5true
2+2=4true
7 6~13
输入样例8:
乱序输入+分值不足100+两份答卷+答卷缺失部分答案。例如:
N:3 #Q:3+2= #A:5
N:2 #Q:2+2= #A:4
T:1 3-7 2-6
S:1 #A:5 #A:22
N:1 #Q:1+1= #A:2
T:2 2-5 1-3 3-2
S:2 #A:5 #A:4
end
输出样例:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
3+2=5true
2+2=22false
7 0~7
2+2=5false
1+1=4false
answer is null
0 0 0~0
输入样例9:
乱序输入+分值不足100+两份答卷+无效的试卷号。例如:
N:3 #Q:3+2= #A:5
N:2 #Q:2+2= #A:4
T:1 3-7 2-6
S:3 #A:5 #A:4
end
输出样例:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
The test paper number does not exist
点击查看代码
import java.util.*;
class Question {
private int number;
private String content;
private String standardAnswer;
public Question(int number, String content, String standardAnswer) {
this.number = number;
this.content = content;
this.standardAnswer = standardAnswer;
}
public boolean judgeAnswer(String answer) {
return answer.equals(standardAnswer);
}
public String toString() {
return content + "~" + standardAnswer;
}
public int getnumber(){
return this.number;
}
}
class ExamPaper {
private List<Question> questions;
private Question question;
private int a;
public ExamPaper(int a) {
this.questions = new ArrayList<>();
this.a = a;
}
public void addQuestion(Question question) {
questions.add(question);
}
public boolean judgeAnswer(int number, String answer) {
return questions.get(number - 1).judgeAnswer(answer);
}
public String getQuestionInfo(int number) {
return questions.get(number - 1).toString();
}
public void sort(){
for(int x=0;x<a-1;x++){
for(int y = 0;y<a-1;y++){
if(questions.get(y).getnumber()>questions.get(y+1).getnumber()){
question = questions.get(y);questions.set(y,questions.get(y+1));questions.set(y+1,question);
}
}
}
}
}
class AnswerSheet {
private ExamPaper examPaper;
private List<String> answers;
private List<Boolean> judgeResults;
public AnswerSheet(ExamPaper examPaper) {
this.examPaper = examPaper;
this.answers = new ArrayList<>();
this.judgeResults = new ArrayList<>();
}
public void saveAnswer(String answer) {
answers.add(answer);
}
public void judgeAnswers() {
for (int i = 0; i < answers.size(); i++) {
String answer = answers.get(i);
boolean result = examPaper.judgeAnswer(i + 1, answer);
judgeResults.add(result);
}
}
public void printResults() {
for (int i = 0; i < answers.size(); i++) {
System.out.println(examPaper.getQuestionInfo(i + 1));
}
for (int i = 0; i < answers.size(); i++) {
System.out.printf("%s",judgeResults.get(i));
if(i==answers.size()-1){
System.out.println();
}else{
System.out.printf(" ");
}
}
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int questionCount = scanner.nextInt();
scanner.nextLine();
ExamPaper examPaper = new ExamPaper(questionCount);
for (int i = 0; i < questionCount; i++) {
String line = scanner.nextLine();
String[] parts = line.split(" #");
int number = Integer.parseInt(parts[0].split(":")[1].trim());
String content = parts[1].split(":")[1].trim();
String standardAnswer =parts[2].split(":")[1].trim();;
examPaper.addQuestion(new Question(number, content, standardAnswer));
}
examPaper.sort();
AnswerSheet answerSheet = new AnswerSheet(examPaper);
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.equals("end")) {
break;
}
String[] answers = line.split(" ");
for (String answer : answers) {
if (answer.startsWith("#")) {
String ans = answer.substring(3);
answerSheet.saveAnswer(ans);
}
}
}
answerSheet.judgeAnswers();
answerSheet.printResults();
}
}
对于第二次的这道题目,当时的我由于思维的固化没有过多的思考,便认为既然是迭代的题目,那么他就应该像c语言一样,所以我便没有进行任何的改进,继续使用着那三个类,最后的结果就是我这道题目非但没有得到分,还把所有设计思路统统抛到脑后,只去寻找代码的内容到底哪里有问题而不是去想想是不是类的设计和分布上出现了问题,这也导致了我对于后续增加的要求更加的有心无力,开始渐渐认为写这道题目就是一种折磨,心态问题的出现是最致命的因素。所以这一道题目我不出意外地没有拿到一分,这也导致我怀疑自己的能力是不是能够应付接下来继续增加的要求。
第三次作业:
第二题的难度我认为就已经有了,不像是之前的基础题。
题目描述
给定一个日期,判定是否为合法日期。如果合法,判断该年是否闰年,该日期是当年第几天、当月第几天、当周第几天、。
给定起始日期与结束日期,判定日期是否合法且结束日期是否早于起始日期。如果均合法,输出结束日期与起始日期之间的相差的天数、月数、念书。
输入格式:
第一行输入一个日期字符串,格式为"YYYY-MM-dd"
第二行输入两个日期字符串,中间使用空格隔开。分别代表开始日期与结束日期。
输出格式:
如果第一行日期字符串非法,输出自定义的错误信息。
如果第一行日期有效,输出相关信息,如果是闰年要输出是闰年。
如果第二行两个日期,只要有一个无效。就输出相关错误信息。
如果第二行两个日期有效且结束日期不早于开始日期,输出相关信息。
输入样例1:
第一行日期非法、第二行有日期非法
2020-02-30
2020-02-30 2020-01-02
输出样例1:
2020-02-30无效!
2020-02-30或2020-01-02中有不合法的日期.
输入样例2:
均有效且合法
2021-02-28
2019-08-01 2020-01-02
输出样例2:
2021-02-28是当年第59天,当月第28天,当周第7天.
2020-01-02与2019-08-01之间相差154天,所在月份相差-7,所在年份相差1.
输入样例3:
日期均有效,但结束日期早于开始日期
2020-02-28
2020-02-02 2020-02-01
输出样例3:
2020-02-28是闰年.
2020-02-28是当年第59天,当月第28天,当周第5天.
2020-02-01早于2020-02-02,不合法!
点击查看代码
import java.util.Scanner;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Main {
public static int[]month_day = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String date = input.next();
String start = input.next();
String end = input.next();
String date1 = number(date);
String start1 = number(start);
String end1 = number(end);
int date2 = Integer.parseInt(date1);
int start2 = Integer.parseInt(start1);
int end2 = Integer.parseInt(end1);
int dateDay = date2 % 100;
int dateMonth = date2 / 100 % 100;
int dateYear = date2 / 10000;
int startDay = start2 % 100;
int startMonth = start2 / 100 % 100;
int startYear = start2 / 10000;
int endDay = end2 % 100;
int endMonth = end2 / 100 % 100;
int endYear = end2 / 10000;
int judgeRun = runYear(dateYear);
if (judgeRun == 1) month_day[1] = 29;
int judgeLeg = judgeDate(dateMonth, dateDay, date2);
if (judgeLeg == 0) {
System.out.println(date + "无效!");
}
else {
if (judgeRun == 1) System.out.println(date + "是闰年.");
int sum_day = daysOfYear(dateMonth, dateDay);
LocalDate startDate = LocalDate.of(2000, 01, 02);
LocalDate endDate = LocalDate.of(dateYear, dateMonth, dateDay);
long days = Math.abs(ChronoUnit.DAYS.between(startDate, endDate)) % 7;
if (days == 0) days = 7;
System.out.println(date + "是当年第" + sum_day + "天,当月第" + dateDay + "天,当周第" + days + "天.");
}
judgeRun = runYear(startYear);
if (judgeRun == 0) month_day[1] = 28;
int judgeLegS = judgeDate(startMonth, startDay, start2);
judgeRun = runYear(startYear);
if (judgeRun == 0) month_day[1] = 28;
if (judgeRun == 1) month_day[1] = 29;
int judgeLegE = judgeDate(startMonth, startDay, end2);
if (judgeLegS == 0 || judgeLegE == 0)
System.out.println(start + "或" + end + "中有不合法的日期.");
else if (start2 > end2) {
System.out.println(end + "早于" + start + ",不合法!");
}
else {
int yearSub = endYear - startYear;
int monthSub = endMonth - startMonth;
LocalDate startDate = LocalDate.of(startYear, startMonth, startDay);
LocalDate endDate = LocalDate.of(endYear, endMonth, endDay);
long days = ChronoUnit.DAYS.between(startDate, endDate);
System.out.print(end + "与" + start + "之间相差" + days + "天,所在月份相差" + monthSub + ",所在年份相差" + yearSub + ".");
}
}
public static String number(String str) {
str = str.trim();
String str2 = "";
if (str != null && !"".equals(str)) {
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) >= 48 && str.charAt(i) <= 57) {
str2 += str.charAt(i);
}
}
}
return str2;
}
public static int runYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) ? 1 : 0;
}
public static int daysOfYear(int month, int day) {
int sum = 0;
for (int i = 0; i < month - 1; i++) {
sum += month_day[i];
}
sum += day;
return sum;
}
public static int judgeDate(int month, int day, int whole) {
if (whole < 100000000 && whole >= 10000000) {
return day >= 1 && day <= month_day[month - 1] ? 1 : 0;
} else {
return 0;
}
}
}
这道题目注重对于日期合法性的检查以及闰年的判断。
我在这里对闰年进行了判断以及在下面使用 judgeDate 方法检查日期是否合法。
随后我在下面完成了检查开始日期和结束日期的合法性、检查开始日期是否早于结束日期以及计算日期之间的差异。
下面是最后一题及其添加的功能
题目描述
设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-2基础上增补或者修改的内容,要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分五种,信息可能会打乱顺序混合输入。
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=5false
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" 。
样例:
3+2=5true
4+6=22false.
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:
简单输入,不含删除题目信息。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:1 20201103 #A:1-5
end
输出样例1:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
20201103 Tom: 0~0
输入样例2:
简单输入,答卷中含多余题目信息(忽略不计)。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:1 20201103 #A:1-2 #A:2-3
end
输出样例3
简单测试,含删除题目信息。例如:
alert: full score of test paper1 is not 100 points
1+1=2true
20201103 Tom: 5~5
输入样例3:
简单测试,含删除题目信息。例如:
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-20201105 Www
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出样例3:
在这里给出相应的输出,第二题由于被删除,输出题目失效提示。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
the question 2 invalid~0
20201103 Tom: 0 0~0
输入样例4:
简单测试,含试卷无效题目的引用信息以及删除题目信息(由于题目本身无效,忽略)。例如:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 3-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出样例4:
输出不存在的题目提示信息。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
non-existent question~0
20201103 Tom: 0 0~0
输入样例5:
综合测试,含错误格式输入、有效删除以及无效题目引用信息。例如:
N:1 +1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出样例5:
在这里给出相应的输出。例如:
wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
the question 2 invalid~0
20201103 Tom: 0 0~0
输入样例6:
综合测试,含错误格式输入、有效删除、无效题目引用信息以及答案没有输入的情况。例如:
N:1 +1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-5
D:N-2
end
输出样例6:
答案没有输入的优先级最高。例如:
wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
answer is null
20201103 Tom: 0 0~0
输入样例7:
综合测试,正常输入,含删除信息。例如:
N:2 #Q:2+2= #A:4
N:1 #Q:1+1= #A:2
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:2-4 #A:1-5
D:N-2
end
输出样例7:
例如:
alert: full score of test paper1 is not 100 points
1+1=5false
the question 2 invalid~0
20201103 Tom: 0 0~0
输入样例8:
综合测试,无效的试卷引用。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:2 20201103 #A:1-5 #A:2-4
end
输出样例8:
例如:
alert: full score of test paper1 is not 100 points
The test paper number does not exist
输入样例9:
无效的学号引用。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201106 Tom
S:1 20201103 #A:1-5 #A:2-4
end
输出样例9:
答案照常输出,判分时提示错误。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
20201103 not found
输入样例10:
信息可打乱顺序输入:序号不是按大小排列,各类信息交错输入。但本题不考虑引用的题目在被引用的信息之后出现的情况(如试卷引用的所有题目应该在试卷信息之前输入),所有引用的数据应该在被引用的信息之前给出。例如:
N:3 #Q:中国第一颗原子弹的爆炸时间 #A:1964.10.16
N:1 #Q:1+1= #A:2
X:20201103 Tom-20201104 Jack-20201105 Www
T:1 1-5 3-8
N:2 #Q:2+2= #A:4
S:1 20201103 #A:1-5 #A:2-4
end
输出样例10:
答案按试卷中的题目顺序输出。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
中国第一颗原子弹的爆炸时间4false
20201103 Tom: 0 0~0
对于这道题,其实我已经放弃了代码的完成,因为我前两次作业所埋下的炸弹已经引爆了,我无法使用仅有的三个类完成所需的要求,所以我开始重新设计类的需求,以及每一个需求是否需要一个类,这两个可不可以放在一个类中等问题,但是当我认为设计好了题目类,试卷类,学生类,答卷类,题库类,试卷管理系统类时我发现还是不够,没办法完成,所以这次作业我还是没有拿到分数,我很后悔。
三:踩坑心得
1.写题目时一定要注重一些细节,例如中英文的符号变换,是否含有空格,以及一些方法的调用等细节问题。
2.在Java中设计是重中之重,在拿到题目或者需求时,一定要先做类的设计和整体的框架,以及如何实现需要用到什么方法,最后才是代码的实现,因为设计就像是大楼的基石,没有他的稳定一切都将轰然倒塌。
四:改进建议
不论写什么题目都先做好类的设计,争取做到可持续和复用。
五、总结
对于这三次的PTA,我认为老师其实是给了我们一个循序渐进的过程,让我们慢慢适应这种新的语言和新的教学方式,题目量虽然是一次次减少,但是题目难度却时一次次提高,使我们能把更多的精力集中在一道题上。我认为这门课程其中一个很重要的能力就是自学能力,而我们这门课程的教学方式正好可以提升我们这一方面的能力,通过线上线下同时学习的方式,我认为这一点很好。最后我想对自己说还是加油吧,认真地花更多的时间学好这一门课程,加油加油加油!