第一次Blog

Anordinarypea發表於2024-04-21

一.前言
在前三次大作業中,設計的均為我們學習生活中常見的答題判題程式,適用於常見的一些網上答題系統,例如我們常見的學習通考試系統。總結前三次大作業,主要知識點第一則為類。利用類能夠很好的解決前三次大作業的問題。在後兩次大作業中則額外考查了動態陣列,連結串列以及hashmap的知識點(因為儲存資訊只好用以上知識),難度對於第一次大作業可謂直線上升。同時對於資訊的獲取也考查到了正規表示式的知識點。總結,前三次大作業難度逐次提升,難但不算很難,題量也適中,但需要花費一定時間,知識點主要考察類的運用,同時也考察到正規表示式的運用,在後兩次大作業中還考察到hashmap,動態陣列,連結串列以及介面的相關知識。

二.設計與分析
由於大作業主要得分點以及考察點都在最後一題,故只分析最後一題。由於設計思路的問題,使用到大量if或者迴圈,複雜度過於巨大(尤其是後兩次大作業),故未使用SourceMontor進行測試
1.第一次大作業的分析:
在第一次大作業中,主要輸入三種資訊:題目數量,題目內容,答題資訊。題目數量僅為一個數字,可以直接透過int Sum=input.nextInt()中的Sum獲取到,而題目內容分為三個部分:題目序號,題目內容以及題目答案,以"#N:"+題號+" "+"#Q:"+題目內容+" "#A:"+標準答案"格式輸入,這時候我們可以先直接獲取整行資訊,利用正規表示式直接查詢獲取三個資訊,也可以使用String.split()的方法進行分割在進行匹配,我這裡使用了前一種方式,設定正規表示式直接查詢,這種方式沒有考慮到輸入資訊錯誤的情況,由於第一次大作業並未設定錯誤資訊的測試點,我便直接忽略了這一風險。使用的正規表示式如下:

其中的serach1和search2用於直接獲取題目序號和題目內容,search3獲取標準答案,然後根據題目數量進行多次迴圈獲取,獲取的內容在相應類中建立一個陣列用於儲存,同時針對題目序號進行排序。而search3同時也可以用於獲取第三個資訊答題資訊的,輸入格式為"#A:"+答案內容。獲取到的答案資訊也儲存到相應類中,這樣第一步獲取資訊就算輕鬆完成了。
以下則為我設計的類圖:

之後進行第二步判題程式的進行,利用輸入的答題資訊中的答案與題目中的標準答案進行對比,以此來判別答題是否正確,這一步我設計為函式放到試卷類Examination這一個類中。判別成功後則使用陣列記入判別的資訊,由於輸出方式與輸入的答題資訊有關,我將輸出函式放到類TextSolve答卷類中,獲取完以上資訊後利用類TextSolve中函式toQuestionString進行輸出,這次大作業就算完成(測試點全部透過)。

2.第二次大作業的分析:
在第二次大作業中則刪去了題目數量這一資訊,同時增加了試卷資訊,即輸入資訊有三:題目資訊,試卷資訊,答卷資訊。資訊方面變化不大,但由於題目數量這一資訊的刪去,我們並不知道具體有多少題目,因此陣列儲存題目就不太可行,這是就需要用到新的知識點,而在這次大作業中我選擇使用了動態陣列,即ArrayList的使用,來進行資訊的儲存,而設計的類也需要更改,這次大作業的類圖如下:

同時我在每個類中都建立了動態陣列ArrayList進行資訊方面的儲存。要儲存資訊則需要先獲取資訊。在這次大作業中的第一難點便是資訊的獲取,同時由於題目增加了三種資訊亂序輸入的情況,因此區別於第一次大作業的資訊獲取,我們需要使用而外的正規表示式匹配輸入的資訊。而輸入的資訊都含有#+字母的字首,依據對字首的檢索就可以輕鬆獲取資訊,同時也可以解決資訊亂序輸入的情況。我在這次使用的正規表示式如下:
其中的search6-8即為對字首的檢索,剩下的則為對資訊的獲取。由於題目中含有end欄位來代表輸入結束,因此我們可以設計一個while迴圈來獲取資訊,檢測到end欄位則結束,由於本次大作業也依舊沒有加入錯誤資訊的輸入,在這裡不做考慮。檢索資訊的程式碼參考結構如下(僅為參考結構,真實程式碼不一):

到這裡完成了第一步獲取資訊,難度不算大,可以輕鬆完成,接下來便是本次大作業的難點,對資訊的輸出。由於多了試卷的總分警示這一行資訊,我們現需要判斷試卷資訊的分數之和是否為100,由於這一段輸出資訊為最上行,我們可以在獲取資訊的迴圈中同時完成分數的計算,完成對上述資訊的輸出。從本次大作業的樣例中不難看出,輸出主要依據答卷中輸入的題目順序而非試卷資訊,即輸出主要依據答卷資訊,因此我將主要的用於輸出函式toQuestionString()放到類AnswerPaper答卷類中,依據上一次大作業的設計,我同時將判題程式放在了TextSolve試卷類中,因此則需要在主函式main中建立關於AnswerPaper答卷類的類的物件的陣列,在AnswerPaper中應用TextSolve試卷類的判別函式進行題目的判別,記錄判別的結果。最後建立boolean型別的陣列儲存判別結果,同時需要建立動態輸出mark記錄所得分數,最後進行輸出。

3.第三次大作業的分析:
在第三次大作業中則額外增加了學生資訊和刪除題目資訊,相較於第二次大作業則需要多增加學生資訊類和刪除類,同時由於題目輸出資訊的難度加大,我專門設定了輸出類用於輸出條件的主要判斷。以下為這次的類圖:

對於第一步獲取資訊同前兩次大作業一樣,由於題目新增了大量錯誤資訊的輸入,我對每一段資訊進行String.split()進行分割,用於判斷資訊的輸入格式,由於輸出"輸入錯誤資訊提示"在最上行,我將其放在獲取資訊的迴圈中。迴圈結構同第二次大作業,以下則為使用到的正規表示式:

獲取到資訊後判別方式同第二次大作業類似,這裡不多做贅述。最大難點在於錯誤資訊的輸入,因此我將使用動態陣列改為hashmap,利用判斷hashmap中的內容進行相應輸出,此為我當初設計的原碼(依據題目設計,過於複雜,待續改進):

三.踩坑心得
1.第一次大作業:由於第一次大作業較為簡單,踩坑點僅為對類的運用不熟悉。
2.第二次大作業:難度相較於第一次更大,輸入的資訊以及判別方式更加艱難,踩坑較多,比如動態陣列為空時會報錯,一個類不能多次使用(否則導致類的屬性改變,只存到一條資訊),輸出方式主要依據答卷資訊而非試卷資訊(在第一次嘗試中我設計的輸出資訊主要依據試卷資訊),並且一些坑持續了很久,讓我花費了大量時間,這也讓我認識到提前做好設計的重要性。
3.第三次大作業:由於難度進一步加大,踩的坑也很多,主要為對於錯誤資訊的輸出存在需要按序號輸出,例如answer is null,需要依據答卷資訊按序號輸出,而我只是單單把這條資訊放在最後輸出。設計的問題原碼如下:

這段原碼導致輸出的answer is null資訊只會出現在其他輸出資訊的最後面,導致部分測試點未透過。同時還有hashmap為空時不能引用,或者進行是否為空的判斷,而在這次大作業使用大量hashmap,在排查錯誤時也耗費大量時間。

四.改進建議
1.對於第一次大作業,由於題目較為簡單。僅需簡化程式碼,刪除多餘的無用程式碼即可
2.對於第二次大作業,難度更大,可以將動態陣列的使用更改為hashmap的使用,對於序號進行查詢,能夠讓輸出資訊更為方便,同時依據答卷序號重複輸入的問題,則可以設定個檢測程式,在輸入時檢測是否已經存在該序號的資訊,檢測成功則可以增加hashmap的儲存避免覆蓋,同時對同一個序號的試卷類進行標記,避免輸出錯誤的資訊。
3.對於第三次大作業,則是思路設計的改進,由於我一開始使用大量hashmap進行儲存,對於題目錯誤資訊按序輸出方面略有缺陷,個人認為可以適當使用hashmap,一部分改為使用連結串列進行儲存,應為連結串列對於序號可以更方便的輸出,而試卷資訊和答卷資訊更適合改為連結串列儲存,可以更好的幫助輸出資訊,減少不必要的條件判斷。同時可以將輸出類中的一部分輸出內容放到對應類中以減少條件判斷,減少複雜程度。例如對於題目內容的輸出可以使用題目類中的輸出函式解決,引數可以增加String型別代表輸入的答案,進行答案的判別同時將判別結果返回並輸出該答題情況,利用迴圈實現輸出內容中的對於題目內容及答案判別的輸出。同時還能獲取判別結果計算分數。

5.總結
對於這三次大作業,主要考察對於類的應用,而經過這三次鍛鍊,也讓我對於類的應用更加熟絡,同時對於正規表示式的運用,動態陣列以及hashmap的運用更為得心應手,同時也讓我認識到對於介面的學習需要進一步加強,對於類的運用也需要多加練習。並且需要改掉看到題目直接寫程式碼的陋習,形成物件導向程式設計的核心素養以及設計思路,對於類的設計更需要系統化,物件化。在這幾次大作業中也有許多獲得優秀成績的學生,說明這幾次大作業並不算很難,對於我也算一種全方面的鍛鍊。