前言
這學期剛剛接觸物件導向程式設計,使用的是java語言。在此之前只接觸過c語言。以我目前的學習程序來看二者的差別更多體現在物件導向的其中一個基本特性上,即封裝性。在c語言中幾乎所有內容都是公開的,java可以有效得規避這點。
學習的知識點
1.知道了類間關係。物件導向程式設計中要根據實際情況合理使用繼承,關聯,聚合,組合,依賴等五類類間關係。選擇合適的類間關係有利於程式碼的維護和使用。
2.知道了類的使用。類可以包含屬性和方法。這使得類可以實現單一職責原則。這項原則在程式設計中尤為重要。另外的,設計類時也要注意封裝性,不能盲目得使用public。同時,部分類需要透過例項呼叫。
3.學習了java包中的部分方法,知道了導包。為了完成PTA作業,學習了regex,Math等包中的方法,便於處理部分問題。
4.學會了管理資料。學習了ArrayList,LinkedList和HashMap的原理和使用。
自我改進的方面
- 增強程式設計的“全域性觀念”。設計程式考慮後續的擴充與維護。
- 拓寬學習方法。對於物件導向的學習不能僅侷限於學校的學習體系,學習網站和AI大模型也是較好的學習途徑。
三次P他的難度逐步加大的同時也根據實際情況增加了越來越多的限制,對學生的應變能力與自學能力有較大要求。
設計分析
第一次PTA大作業:
1)題目要求
7-5 答題判題程式-1
分數 74
困難
作者 蔡軻
單位 南昌航空大學
設計實現答題程式,模擬一個小型的測試,要求輸入題目資訊和答題資訊,根據輸入題目資訊中的標準答案判斷答題的結果。
輸入格式:
程式輸入資訊分三部分:
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
設計建議:
以下是針對以上題目要求的設計建議,其中的屬性、方法為最小集,實現程式碼中可根據情況新增所需的內容:
題目類(用於封裝單個題目的資訊):
屬性:題目編號、題目內容、標準答案-standardAnswer
方法:資料讀寫set\get方法、
判題方法(答案-answer):判斷答案-answer是否符合標準答案-standardAnswer
試卷類(用於封裝整套題目的資訊)
屬性:題目列表(題目類的物件集合)、題目數量
方法:判題方法(題號-num、答案-answer):判斷答案-answer是否符合對應題號的題目標準答案-standardAnswer
儲存題目(題號-num、題目-question):將題目儲存到題目列表中,儲存位置與num要能對應
答卷類(用於封裝答題資訊)
屬性:試卷(試卷類的物件)、答案列表(儲存每一題的答案)、判題列表(儲存每一題的判題結果true/false)
方法:判題方法(題號-num):判斷答案列表中第num題的結果是否符合試卷中對應題號的題目標準答案
輸出方法(題號-num):按照題目的格式要求,輸出題號為num的題目的內容和答題結果。
儲存一個答案(題號-num,答案-answer):儲存題號為num的題目的答題結果answer。
2)個人設計
由於第一次作業給出了設計建議,本次作業按照建議進行設計。
針對題目資訊設計了exercise類,其中包含了題號,題目內容和正確答案三個屬性。除構造方法等存取類方法外,還設計了一個根據輸入的答案判斷答案對錯的方法。
`class exercise{
private int NO = 0;//題號
private String Content = "";//題目內容
private String standardAnswer = "";//正確答案
public int getNO() {
return NO;
}
public void setNO(int NO) {
this.NO = NO;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
public boolean judge(String answer){//判斷對錯
return answer.equals(this.standardAnswer);
}
}`
針對試卷資訊設計了paper類,其中包含了總題數和題目類陣列兩個屬性。除構造方法等存取類方法外,還設計了一個根據題目順序和答案判斷對應題目的答案的對錯的方法。
`class paper {
public int sum;//總題數
public exercise[] exe;//題目陣列
public boolean Judge(int num, String answer) {
return exe[num].judge(answer);
}
public void save(int num, String question) {
exe[num].setNO(num);
exe[num].setContent(question);
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
exe = new exercise[sum + 1];
}
}`
針對答卷資訊設計了AnswerPaper類,其中包含了試卷,答案列表和判斷列表三個屬性。只有存取類方法。
`class AnswerPaper {
public paper Paper;//試卷
private String[] answer;//答案列表
private boolean[] judge;//判斷列表
public AnswerPaper(int sum) {
this.answer = new String[sum + 1];
this.judge = new boolean[sum + 1];
}
public void judge(int num) {
this.judge[num] = Paper.exe[num].judge(answer[num]);
}
public void saveAnswer(int num, String answer) {
this.answer[num] = answer;
}
public void setPaper(paper paper) {
Paper = paper;
}
public void setAnswer(String[] answer) {
this.answer = answer;
}
public void setJudge(boolean[] judge) {
this.judge = judge;
}
public String[] getAnswer() {
return answer;
}
public boolean[] getJudge() {
return judge;
}
}`
3)設計分析:
由於本次作業是第一次大作業,本人對於程式設計經驗欠缺,造成了較大的設計缺陷:
- 設計的類中部分屬性為public,這不符合物件導向的封裝性。
- 沒有考慮程式的後續迭代,部分類設計僅適用於當前作業,而在後續作業無法繼續使用。如因為本題給出了總題數,在paper類設計中就簡單得將題目存在以總題數為長度的陣列中,沒有考慮到後續題目數量的確定和試卷中題目的順序。
第二次PTA大作業
1)題目要求
7-4 答題判題程式-2
分數 73
困難
作者 蔡軻
單位 南昌航空大學
設計實現答題程式,模擬一個小型的測試,以下粗體字顯示的是在答題判題程式-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,建議增加答題類,類的內容以及類之間的關聯自行設計。
題目相當於第一次作業更加複雜:
- 輸入的三種資訊可以亂序混合輸入
- 由一張試卷演變成了多張試卷,每張試卷資訊都需要儲存
- 存在答卷沒有答案或多餘答案的情況
- 新增試卷總分預警
- 空答案的答卷有單獨的輸出情況
- 新增了判分資訊的輸出
2)個人設計
針對題目類,本次作業整體延用了上次作業的exercise類
`class exercise{
private int NO;//題目編號
private String Content;//題目內容
private String standardAnswer;//正確答案
public exercise(int NO, String content, String standardAnswer) {
this.NO = NO;
Content = content;
this.standardAnswer = standardAnswer;
}
public int getNO() {
return NO;
}
public void setNO(int NO) {
this.NO = NO;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
public boolean judge(String answer){//判斷對錯
return answer.equals(this.standardAnswer);
}
}`
針對試卷類,本次作業與上次相比變化較大。有試卷編號,題目號與分值組成的HashMap,試卷總分和儲存試卷號順序的ArrayList。使用HashMap是為了將題目編號與題目分值相關聯;使用ArrayList是因為本次作業未給出試卷的題目總數;試卷總分是為了實現試卷總分預警。
`class paper {
private static int NoPaper;//試卷編號
private HashMap<Integer, Integer> ExerciseAndGrade;// key為題目編號,value為題目分值
private int SumGrade = 0;
private ArrayList
public paper(int noPaper) {
NoPaper = noPaper;
ExerciseAndGrade = new HashMap<>(); // 初始化ExerciseAndGrade
}
public void setExerciseAndGrade(int NOEXE, int Grade) {
ExerciseAndGrade.put(NOEXE, Grade);
SumGrade = SumGrade + Grade;
}
public ArrayList<Integer> getEXES() {
return EXES;
}
public void addEXES(int NO) {
EXES.add(NO);
}
public int getSumGrade() {
return SumGrade;
}
public HashMap<Integer, Integer> getExerciseAndGrade() {
return ExerciseAndGrade;
}
}`
針對答卷類,本次作業對其進行了重新設計。設計了答卷編號和儲存答案的ArrayList兩個屬性。使用ArrayList是因為本次作業未給出試卷的總題目數。
`class AnswerPaper {
private int _NoPaper;//答卷編號
private ArrayList
public AnswerPaper(int _NoPaper) {
this._NoPaper = _NoPaper;
Answers = new ArrayList<>(); // 初始化Answers
}
public void setAnswer(String Answer) {
Answers.add(Answer);
}
public int get_NoPaper() {
return _NoPaper;
}
public void set_NoPaper(int _NoPaper) {
this._NoPaper = _NoPaper;
}
public ArrayList<String> getAnswers() {
return Answers;
}
public void setAnswers(String answers) {
Answers.add(answers);
}
}`
在Main類中定義了儲存題號和題目例項的exerciseMap,為HashMap;儲存試卷編號與試卷例項的PaperMap,為HashMap;儲存試卷編號的PaperSum,為ArrayList;儲存答卷例項的answerPaper,為ArrayList。
//題目類 static HashMap<Integer,exercise> exerciseMap=new HashMap<>();//key題號,value題目 //試卷類 static HashMap<Integer,paper> PaperMap=new HashMap<>(); //key編號 value試卷 static ArrayList<Integer> PaperSum = new ArrayList<>();//存試卷編號 //答卷類 static ArrayList<AnswerPaper> answerPaper=new ArrayList<>();//答卷的陣列
在main方法中對於輸入資料的處理與上次作業有較大不同。
由於輸入格式的改變,輸入時先對輸入資料關鍵字進行匹配與分類,根據不同的類別處理資訊。
`String Str = "";
while (sc.hasNextLine()) {
Str = sc.nextLine();
if(Str.equals("end")) {
break;
}
if(Str.contains("#N")){
String[] parts = Str.split("#N:| #Q:| #A:");
exercise EXE = new exercise(Integer.parseInt(parts[1]),parts[2],parts[3]);
exerciseMap.put(Integer.parseInt(parts[1]),EXE);
} else if (Str.contains(("#T"))) {
String[] parts = Str.split("#T:|-| ");
paper PAPER = new paper(Integer.parseInt(parts[1]));
for(int i = 2;i < parts.length;i = i + 2) {
PAPER.setExerciseAndGrade(Integer.parseInt(parts[i]),Integer.parseInt(parts[i + 1]));
PAPER.getEXES().add(Integer.parseInt(parts[i]));
}
PaperMap.put(Integer.parseInt(parts[1]),PAPER);
if(!PaperSum.contains(Integer.parseInt(parts[1]))) {
PaperSum.add(Integer.parseInt(parts[1]));
}
} else if(Str.contains("#S")){
String[] parts = Str.split("#S:| #A:");
AnswerPaper Anpaper = new AnswerPaper(Integer.parseInt(parts[1]));
for(int i = 2; i <= parts.length - 1;i ++){
Anpaper.setAnswer(parts[i]);
}
answerPaper.add(Anpaper);
}
}`
3)設計分析
- 吸取上次作業的教訓,本次作業對所有屬性都進行了封裝。
- 由於不知道各類資訊的具體數量,本次作業靈活使用ArrayList處理資料。同時,對於部分有聯絡的資訊採用了HashMap進行儲存。
- 各類基本實現了單一職責。
- 對於上次作業的結構進行了較大改變,使其符合題目要求的同時更好得進行擴充。
第三次PTA大作業
1)題目要求
7-3 答題判題程式-3
分數 84
困難
作者 蔡軻
單位 南昌航空大學
設計實現答題程式,模擬一個小型的測試,以下粗體字顯示的是在答題判題程式-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。
本題暫不考慮出現多張答卷的資訊的情況。
題目在上次作業的基礎上進行迭代:
- 新增了刪除題目資訊。被刪除的題目有單獨的輸出方法。
- 新增了學生資訊,需要單獨儲存。
- 答卷資訊中新增了學生學號的屬性。
- 存在題目引用錯誤的情況。
- 答卷的題目與試卷題目順序相對應。
2)個人設計
題目類與上次作業相比變化不大
`class exercise{
private int NO;//題目編號
private String Content;//題目內容
private String standardAnswer;//正確答案
public exercise(int NO, String content, String standardAnswer) {
this.NO = NO;
Content = content;
this.standardAnswer = standardAnswer;
}
public int getNO() {
return NO;
}
public void setNO(int NO) {
this.NO = NO;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
public boolean judge(String answer){//判斷對錯
return answer.equals(this.standardAnswer);
}
}`
試卷類與上次作業相比變化不大
`class paper {
private static int NoPaper;//試卷編號
private HashMap<Integer, Integer> ExerciseAndGrade;// key為題目編號,value為題目分值
private int SumGrade = 0;
private ArrayList
public paper(int noPaper) {
NoPaper = noPaper;
ExerciseAndGrade = new HashMap<>(); // 初始化ExerciseAndGrade
}
public void setExerciseAndGrade(int NOEXE, int Grade) {
ExerciseAndGrade.put(NOEXE, Grade);
SumGrade = SumGrade + Grade;
}
public ArrayList<Integer> getEXES() {
return EXES;
}
public void addEXES(int NO) {
EXES.add(NO);
}
public int getSumGrade() {
return SumGrade;
}
public HashMap<Integer, Integer> getExerciseAndGrade() {
return ExerciseAndGrade;
}
}`
答卷類與上次作業相比變化較大。增加了學生學號與答案順序的屬性,答案順序為ArrayList。答案順序屬性是為了適應改變的要求。
`class AnswerPaper {
private int _NoPaper;//答卷編號
private HashMap<Integer,String> Answers;//key為答卷的試卷題目順序號,value為答案 // 答案的陣列
private int AnswerStuID;
private ArrayList
public AnswerPaper(int _NoPaper) {
this._NoPaper = _NoPaper;
Answers = new HashMap<>(); // 初始化Answers
AnswerOrder = new ArrayList<>();
}
public void setAnswer(int NO,String Answer) {
Answers.put(NO,Answer);
}
public int get_NoPaper() {
return _NoPaper;
}
public void set_NoPaper(int _NoPaper) {
this._NoPaper = _NoPaper;
}
public HashMap<Integer, String> getAnswers() {
return Answers;
}
public void setAnswers(int NO,String answers) {
Answers.put(NO,answers);
}
public int getAnswerStuID() {
return AnswerStuID;
}
public void setAnswerStuID(int answerStuID) {
AnswerStuID = answerStuID;
}
public ArrayList<Integer> getAnswerOrder() {
return AnswerOrder;
}
public void AnswerOrderAdd(int NO) {
AnswerOrder.add(NO);
}
}`
針對學生資訊,新增學生類。包含學生學號與學生姓名兩個屬性。只有基本的存取方法。
`class student {
private int studentID;
private String name;
public student(int studentID, String name) {
this.studentID = studentID;
this.name = name;
}
public student() {
}
public int getStudentID() {
return studentID;
}
public void setStudentID(int studentID) {
this.studentID = studentID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}`
針對刪除題目資訊,新增刪除題目類。因為被刪除題目在後續也需要輸出相關的題目資訊,不能直接將其刪除,使用新增類來儲存資訊。刪除題目資訊類只包含被刪除題目的題號一個屬性和基本的存取方法。
`class exerciseBeDeleted {
int delNO;
public exerciseBeDeleted(int delNO) {
this.delNO = delNO;
}
public int getDelNO() {
return delNO;
}
public void setDelNO(int delNO) {
this.delNO = delNO;
}
}`
考慮到題目需要判斷輸入資訊是否有效,新增判斷資訊是否有效類。包含所需判斷的資訊一個屬性和各種輸入方法有效性判斷的方法。
`class judgevalid {
private String input;
public judgevalid(String input) {
this.input = input;
}
public String getInput() {
return input;
}
public boolean exerciseValid() {
String regex = "^#N:\\d+ #Q:.* #A:.*$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public boolean paperValid() {
String regex = "^#T:\\d+(( \\d+-\\d+)+)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public boolean studentValid() {
String regex = "^#X:((\\d+) ((\\w+)-(\\d+))+ (\\w+))";//-(\\\\d+) (\\\\w+)(?:-\\\\d+ \\\\w+)*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return true;
//return matcher.matches();
}
public boolean answerPaperValid() {
String regex = "^#S:\\d+ \\d+( #A:\\d*-[^\\s]*)*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
public boolean delExeValid() {
String regex = "#D:N-\\d+$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
}`
為了符合題目要求,在Main方法中增加以下方法
- 判斷題目是否被刪除的方法。
public static boolean ExeBeDel(int EXENO) { for(int i = 0;i < delEXE.size();i ++) { if(delEXE.get(i).getDelNO() == EXENO) { return true; } } return false; }
- 精確獲得學生資訊在陣列中位置的方法。
public static int AnStuID(int ID,ArrayList<student> Stu) { for(int i = 0;i < Stu.size();i ++) { if(Stu.get(i).getStudentID() == ID) { return i; } } return -1; }
在Main方法中增加了儲存學生例項的studentList,為ArrayList和儲存刪除題目例項的delEXE,為ArrayList
//學生陣列 static ArrayList<student>studentList = new ArrayList<>(); //刪除的題目類 static ArrayList<exerciseBeDeleted> delEXE = new ArrayList<>();//被刪除的題目的陣列
3)設計分析
- 本次作業在上次作業延用的基礎上再擴充。
- 在Main類裡設計方法,使邏輯更清晰。
踩坑心得
- 在第一次作業中,程式的結構設計較差,程式只適用於當前作業,導致後續作業需要重新設計,造成巨大麻煩。日後的程式設計需要先設計好結構。
- 在第一次作業中沒有對類的屬性進行封裝。日後程式設計要考慮封裝性。
- 在第二次和第三次作業中資料的獲取呼叫太多方法,顯得過於冗長難以辨別。日後可以透過設計方法來統一進行部分資料的獲取。
for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { //j小於對應答卷的題目數時 if(answerPaper.get(i).getAnswers().size() < j + 1) { System.out.println("answer is null"); } else { System.out.printf("%s~%s~%s\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).getContent(),answerPaper.get(i).getAnswers().get(j),exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).judge(answerPaper.get(i).getAnswers().get(j))); } }//答卷的試卷號匹配題目號,題目號匹配題目和答案
改進建議
1. 部分重複冗長的方法呼叫,嘗試編寫方法解決。
如以下部分可以設計方法獲取需要的值
for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { //j小於對應答卷的題目數時 if(answerPaper.get(i).getAnswers().size() < j + 1) { System.out.println("answer is null"); } else { System.out.printf("%s~%s~%s\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).getContent(),answerPaper.get(i).getAnswers().get(j),exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j)).judge(answerPaper.get(i).getAnswers().get(j))); } }//答卷的試卷號匹配題目號,題目號匹配題目和答案
2. 將部分內容寫成方法避面主函式過於臃腫。
如main裡的輸入儲存可以單獨寫成方法。
`String Str = "";
while (sc.hasNextLine()) {
Str = sc.nextLine();
if(Str.equals("end")) {
break;
}
//題目資訊的輸入
if(Str.contains("#N")){
judgevalid Judge = new judgevalid(Str);
if(Judge.exerciseValid()) {
String[] parts = Str.split("#N:| #Q:| #A:");
exercise EXE = new exercise(Integer.parseInt(parts[1]), parts[2], parts[3]);
exerciseMap.put(Integer.parseInt(parts[1]), EXE);
} else {
System.out.printf("wrong format:%s\n",Str);
}
//試卷資訊的輸入
} else if (Str.contains(("#T"))) {
judgevalid Judge = new judgevalid(Str);
if(Judge.paperValid()) {
String[] parts = Str.split("#T:|-| ");
paper PAPER = new paper(Integer.parseInt(parts[1]));
for (int i = 2; i < parts.length; i = i + 2) {
PAPER.setExerciseAndGrade(Integer.parseInt(parts[i]), Integer.parseInt(parts[i + 1]));
PAPER.getEXES().add(Integer.parseInt(parts[i]));
}
PaperMap.put(Integer.parseInt(parts[1]), PAPER);
if (!PaperSum.contains(Integer.parseInt(parts[1]))) {
PaperSum.add(Integer.parseInt(parts[1]));
}
} else {
System.out.printf("wrong format:%s\n",Str);
}
//答卷資訊的輸入
} else if(Str.contains("#S")) {
judgevalid Judge = new judgevalid(Str);
if(Judge.answerPaperValid()) {
String[] parts = Str.split("#S:| #A:| |-");
AnswerPaper Anpaper = new AnswerPaper(Integer.parseInt(parts[1]));
Anpaper.setAnswerStuID(Integer.parseInt(parts[2]));
for (int i = 3; i < parts.length - 1; i = i + 2) {
Anpaper.setAnswer(Integer.parseInt(parts[i]),parts[i + 1]);
Anpaper.AnswerOrderAdd(Integer.parseInt(parts[i]));
}
answerPaper.add(Anpaper);
} else {
System.out.printf("wrong format:%s\n",Str);
}
//學生資訊的輸入
} else if (Str.contains("#X")) {
judgevalid Judge = new judgevalid(Str);
if(Judge.studentValid()) {
String[] parts = Str.split("#X:| |-");
for(int i = 1;i < parts.length - 1;i = i + 2) {
student newStudnt = new student(Integer.parseInt(parts[i]),parts[i + 1]);
studentList.add(newStudnt);
}
} else {
System.out.printf("wrong format:%s\n",Str);
}
//刪除題目資訊的輸入
} else if (Str.contains("#D")) {
judgevalid Judge = new judgevalid(Str);
if(Judge.delExeValid()) {
//String[]
String[] parts = Str.split("-");
exerciseBeDeleted delexe = new exerciseBeDeleted(Integer.parseInt(parts[1]));
delEXE.add(delexe);
}
}
}`
3. 保證完成題目要求的同時避免重複程式碼。
如輸出時為了保證輸出次序而使用了重複程式碼
for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { //j小於對應答卷的題目數時 if (answerPaper.get(i).getAnswers().size() < j + 1) { System.out.println("answer is null"); } else if (!exerciseMap.containsKey(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j))) { System.out.printf("non-existent question~0\n"); } else if (ExeBeDel(exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO())) { //System.out.printf("the question %d invalid~0\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO()); } else { String exeToprint = exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getContent(); String answerToprint = answerPaper.get(i).getAnswers().get(answerPaper.get(i).getAnswerOrder().get(j)); boolean judgeToprint = exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).judge(answerPaper.get(i).getAnswers().get(answerPaper.get(i).getAnswerOrder().get(j))); System.out.printf("%s~%s~%s\n",exeToprint,answerToprint,judgeToprint); } } for(int j = 0; j < PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().size(); j ++) { if (answerPaper.get(i).getAnswers().size() < j + 1) { //System.out.println("answer is null"); } else if (!exerciseMap.containsKey(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(j))) { //System.out.printf("non-existent question~0\n"); } else if (ExeBeDel(exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO())) { System.out.printf("the question %d invalid~0\n",exerciseMap.get(PaperMap.get(answerPaper.get(i).get_NoPaper()).getEXES().get(answerPaper.get(i).getAnswerOrder().get(j) - 1)).getNO()); } }